I'm trying to extend localStorage w/ the following...
localStorage.prototype.setItem2 = function(key,value) {
localStorage.setItem(key,value);
}
I'm getting "localStorage.prototype is null." Am I doing this correctly? Thanks!
localStorage is an instance of the Storage object. Try Storage.prototype.setItem2 or Object.getPrototypeOf(localStorage).setItem2
You can directly set it by :
localStorage.setItem2 = function(key, value) {
// do something
}
or use Storage.prototype
Before you do so, make sure you are not overwriting any existing property. This is to prevent any overwriting for future enhancements to the API by the browsers.
LocalStorage and sessionStorage Objects implements from Storage Interface.
You can extend the Storage through prototype.
Storage.prototype.removeItems = function () {
for(item in arguments) {
this.removeItem(arguments[item]);
}
};
Refer to Article:
HTML5: Storage APIs
Related
I was looking at the sample code for the tutorial at https://forge.autodesk.com/blog/custom-window-selection-forge-viewer-part-iii which is located at https://github.com/Autodesk-Forge/forge-rcdb.nodejs/blob/master/src/client/viewer.components/Viewer.Extensions.Dynamic/Viewing.Extension.SelectionWindow/Viewing.Extension.SelectionWindow.Tool.js as well as the documentation at https://developer.autodesk.com/en/docs/viewer/v2/reference/javascript/toolinterface/ --- Most of these functions are getting called properly in my tool such as handleSingleClick, handleMouseMove, handleKeyDown, and so on, but two of them are not getting hit -- handleButtonDown and handleButtonUp. I was using viewer version 3.3.x but I have updated to use 4.0.x thinking that that might help to resolve the problem, but the same issue occurs in both versions. Thanks for any help.
The following code block from theAutodesk.Viewing.ToolController#__invokeStack(), _toolStack stands for activated tools in the ToolController, the method stands for callback functions started with handle, i.e. handleSingleClick, handleMouseMove, handleKeyDown, handleButtonDown, handleButtonUp, etc.
for( var n = _toolStack.length; --n >= 0; )
{
var tool = _toolStack[n];
if( tool[method] && tool[method](arg1, arg2) )
{
return true;
}
}
Based on my experience, if there is a handle function such as handleButtonDown or handleButtonUp executed before your custom tools' and returned true, then your handles will never be called.
Fortunately, Forge Viewer (v3.2) starts invoking a priority mechanism for custom tools registered in ToolController. ToolController will use the priority number to sort the tools in it, and the priority number of each tool is 0 by default. You can override the priority to make your tools be hit before other tools like this way, to add a function getPriority() to return a number greater than 0:
this.getPriority = function() {
return 100;
};
I found out that when using ES6 and the class syntax, extending your tool from Autodesk.Viewing.ToolInterface will prevent the overrides to work properly, probably because it is not implemented using prototype in the viewer source code.
You can simply create a class and implement the methods that are of interest for your tool:
// KO: not working!
class MyTool extends Autodesk.Viewing.ToolInterface {
getName () {
return 'MyTool'
}
getNames () {
return ['MyTool']
}
handleButtonDown (event, button) {
return false
}
}
// OK
class MyTool {
getName () {
return 'MyTool'
}
getNames () {
return ['MyTool']
}
handleButtonDown (event, button) {
return false
}
}
There has been a change in the click behavior in the model browser from version 2 to version 3 of the Forge Viewer. In v2, a single click would select the elements and a double click would zoom to the selected elements. In v3, a single click will zoom to the elements. Sometimes this is great, but often it would be nice to disable this behavior. Is there an easy way to do this today? And if not, could it be possible to add a disableZoomOnSelection function to the viewer API?
I know that the eyes in the browser will take care of the show and hide elements, but it’s very easy to klick in the three by accident and suddenly the viewer zoom without the user intention.
Regards
Frode
I dig that code for you looking at the implementation of the ViewerModelStructurePanel that I was exposing in that article: Supporting multiple models in the new ModelStructurePanel
Events that occur in the tree are mapped to predefined actions through the options.docStructureConfig object, so the workaround is to instantiate a new ViewerModelStructurePanel with the desired options:
viewer.addEventListener(Autodesk.Viewing.OBJECT_TREE_CREATED_EVENT, () => {
var options = {
docStructureConfig: {
// go with default, which is viewer.select(node)
// click: {
// onObject: ["toggleOverlayedSelection"]
//},
clickShift: {
onObject: ["toggleMultipleOverlayedSelection"]
},
clickCtrl: {
onObject: ["toggleMultipleOverlayedSelection"]
}
}
}
var customModelStructurePanel =
new Autodesk.Viewing.Extensions.ViewerModelStructurePanel(
viewer, 'Browser', options)
viewer.setModelStructurePanel(customModelStructurePanel)
})
The double-click however is not linked to an event in the current implementation, so for a more powerful customization I would recommend you replace the whole implementation by a custom one as exposed in the article and implement desired action handlers. I implemented it as drop-in replacement, so in that case you just need to include it to your html after the viewer script and don't have to replace the model browser in OBJECT_TREE_CREATED_EVENT
The model browser receives an options object in its constructor. There, you can specify the actions for different events (click, clickCtrl, clickShift, etc).
To set the old behavior you can try the following:
var options = {};
options.docStructureConfig = {
"click": {
"onObject": ["isolate"]
},
"clickCtrl": {
"onObject": ["toggleVisibility"]
}
};
NOP_VIEWER.setModelStructurePanel(new ave.ViewerModelStructurePanel(NOP_VIEWER, "", options));
NOP_VIEWER can be replaced with your own viewer variable.
I would like to ask if there's any significant difference/performance issue for detecting using the following two methods:
Let's say we're testing for 3d transforms.
Using the new function that Modernizr 3 offers:
Modernizr.on('csstransforms3d', function(result) {
if (result) {
element.className = 'myFirstClass';
}
else {
element.className = 'mySecondClass';
}
});
And with the standard way:
if (Modernizr.csstransforms3d) {
element.className = 'myFirstClass';
} else {
element.className = 'mySecondClass'
}
The Modernizr.on function is only (or mainly) for asynchronous detects and deferred actions. See the full explanation and example by #stucox for more details.
csstransforms3d is not async, and available right away. There would be no reason to be using the on event callback method for it. The function is rather inefficient with setTimeout() calls which aren't good for performance.
Only use on for deferred events on async detects.
They aren't really comparable because depending on the situation, one will always be better suited than the other. Performance isn't really the issue.
The standard way, checking Boolean values in a Dictionary is an extremely fast operation. If you have a function that gets executed in reaction to some user interaction, this will be the best way to get feature info. For example:
$('#showVideo').on('click', function() {
if (Modernizr.video) {
// load HTML5 video
}
else {
// load Flash video
}
});
Similarly, listening to JS events is very efficient. What the new event-based model in Modernizr allows is for you to react to the Modernizr tests completing. This is great if your site needs to make changes ASAP when feature detection data is available. For example:
Modernizr.on('draganddrop', function(result) {
if (!result) {
alert('This site requires Drag and Drop. Please update your browser.')
}
});
Previously you had to watch for DOM updates on the <body> and check the classes in order to get this information.
I've been reading up on web components and am pretty intrigued by the nascent spec. Does anyone know if there is any support for 2-way data binding in the DOM, without having to use Polymer? An example would be appreciated.
Object.observe is a potential new way to do databinding in javascript. This feature is scheduled for Ecmascript 7(javascript), but some browsers currently support it, check here. Also check out this html5rocks article on object.observe
No, data binding isn't part of the Web Components spec.
You can of course implement data binding yourself using native JavaScript event listeners, and possibly the Proxy object, but it's probably best not to re-invent the wheel: if you want data binding, choose one of the many JavaScript frameworks out there which supports that. Polymer, React, Angular, and Vue are some recent examples of such libraries.
I've been playing around with this over the last few days. You can create a StateObserver class, and extend your web components from that. A minimal implementation looks something like this:
// create a base class to handle state
class StateObserver extends HTMLElement {
constructor () {
super()
StateObserver.instances.push(this)
}
stateUpdate (update) {
StateObserver.lastState = StateObserver.state
StateObserver.state = update
StateObserver.instances.forEach((i) => {
if (!i.onStateUpdate) return
i.onStateUpdate(update, StateObserver.lastState)
})
}
}
StateObserver.instances = []
StateObserver.state = {}
StateObserver.lastState = {}
// create a web component which will react to state changes
class CustomReactive extends StateObserver {
onStateUpdate (state, lastState) {
if (state.someProp === lastState.someProp) return
this.innerHTML = `input is: ${state.someProp}`
}
}
customElements.define('custom-reactive', CustomReactive)
class CustomObserved extends StateObserver {
connectedCallback () {
this.querySelector('input').addEventListener('input', (e) => {
this.stateUpdate({ someProp: e.target.value })
})
}
}
customElements.define('custom-observed', CustomObserved)
<custom-observed>
<input>
</custom-observed>
<br />
<custom-reactive></custom-reactive>
fiddle here
I like this approach because it occurs directly between precisely those elements you want to communicate with, no dom traversal to find data- properties or whatever.
One way: $0.model = {data}; setter on $0 assigns $0.data, responding to the update, and the other way: $1.dispatchEvent(new CustomEvent('example', {detail: $1.data, cancelable: true, composed: true, bubbles: true})); with $0.addEventListenever('example', handler) gives 2 way data binding. The data object is the same, shared on 2 elements, events and setters allow responding to updates. To intercept updates to an object a Proxy works model = new Proxy(data, {set: function(data, key, value){ data[key] = value; ...respond... return true; }}) or other techniques. This addresses simple scenarios. You might also consider looking at and reading the source for Redux, it provides conventions that seem relatively popular. As Ajedi32 mentions reinventing the wheel for more complex scenarios is not so practical, unless it's an academic interest.
I am developing NPAPI Plugin for Firefox on windows. here is the my java script:
document.addEventListener('load', documentLoad, true);
function loadPlugin(doc)
{
var objWebMon = doc.getElementById("my_firefox");
if(!objWebMon)
{
var objWebMonEmbed = doc.createElement('embed');
objWebMonEmbed.setAttribute('id', 'my_firefox');
objWebMonEmbed.setAttribute('type', 'application/npplugin');
objWebMonEmbed.setAttribute('style', 'height: 10px; width:10px; display:block;');
if(doc.body)
{
doc.body.insertBefore(objWebMonEmbed, doc.body.firstChild);
}
}
}
function documentLoad(event) {
try
{
var doc = event.originalTarget; // doc is document that triggered "onload" event
loadPlugin(doc);
var myplugin = doc.getElementById('my_firefox');
if(myplugin)
{
myplugin();
myplugin.myAction();
}
} catch(err)
{
}
}
as I am calling myplugin()
bool ScriptablePluginObject::InvokeDefault(const NPVariant *args, uint32_t argCount, NPVariant *result)
gets called sucessfully but on calling function myplugin.myAction()
bool ScriptablePluginObject::Invoke(NPIdentifier name, const NPVariant *args,
uint32_t argCount, NPVariant *result)
function doesn't called. I have declared myAction inside ScriptablePluginObject::HasProperty(NPIdentifier name) even HasProperty method is not getting called.
Inside catch block i am getting this error. TypeError: fasso.myAction is not a function.
Here are a couple of things to try:
Use an object tag instead of an embed -- I've had more consistent success with object tags, despite the wide popularity of using embed
Never ever ever set the type of an object or embed tag before you add it to the DOM -- doing so causes it to instantiate the plugin and then puts it in a kinda weird state when it gets moved. I don't think this is causing your issue this time, but it's worth trying.
You may need a slight delay between inserting hte plugin into the DOM and using it. Try adding a setTimeout with a delay of 50ms and accessing the plugin in the callback function.
Honestly, #3 is the one I think most likely will make a difference, but I present the other two as they have bitten me on weird things in the past. Good luck!