SugarCRM popup window snapshotForm - javascript

My company has a customer who needs some somewhat complex asset system of self referencing elements. Think of it like a building that has the walls, made of bricks, it has a heating system with a boiler and pipes and radiators and each of these are divided into components too. Each such component, the building, the wall and it's bricks, are stored separately as instances of the asset module.
When filling out the relationship between these assets, you can use the usual pop-up selector window doodad thing, but as soon as we try searching for anything, the system suddenly starts screaming about navigating away from the page.
Now I've traced down exactly what's going on here, there's a JS function defined in src_files\include\javascript\sugar_3.js called snapshotForm that records what the popup form contains on load and then it compares this recorded value with it's state on-close or navigate away to see if it's ok to just move on or if it should throw a tantrum.
Now I can't see anywhere in the module, either sugar/custom/module/udef_asset or sugar/module/udef_asset where anything would get in the way of this snapshot, so my question is simple:
Where can I update the snapshot in a way that ensures the whole page has loaded first? Does anyone have any alternative ideas?

I've figured out the solution to my problem, it was due to a dependant dropdown in the child Create form.
The dropdown had a blank default value and thus was being snapshotted with that blank value. However, once the Sugar systems got a second glance, they realised "hey, you can't be blank, that's not allowed value considering your dependencies!" and thus changed it.
Therefore, on searching for another record, it threw the confirmation.
To find the error I ran the following in the Chrome js console:
snapshotForm(document.getElementById("form_QuickCreate_udef_asset"))
which showed me what the current snapshot would be and:
editViewSnapshots[document.getElementById("form_QuickCreate_udef_asset").id]
which showed me the original snapshot taken. I spotted the error as being in the somewhat complex string ...s_1_nameasset_statusDraftasset_imagedescriptio... where we find the asset_status = Draft bit. In the original, it didn't have the Draft there.
To fix, I could have added blank as an option to the default dependant options, but instead I set the value as default away from blank so that it would load in with the appropriate value.

Related

Angular Elements WebComponents external DOM Changes

TL;DR: Deleting the DOM Element of a custom Element created with Angular Elements will lead to sub-routers not loading components
First, the code is available at Github.
Sadly, I did not get a stackblitz version running, but locally, after a clone, npm install and ng serve it should run fine.
About the general structure:
The Project shows an example of a WebComponent exposed by an Angular App via Elements.
The WebComponent is used in the index.html, which is referred as container Application.
The use case here is a little bit constructed, but the navigation that occurs, when clicking
on the two top bottoms is comparable to the real world use case.
Normally this WebComponent would have been used in an AngularJS legacy Application. Since there are many overlappings between the two root views (overview1 overview2) it is used in two AngularJS components, in between ui-router handled navigation. This means, that exactly this constructed actions happen. The DOM Elements will be deleted and re-added.
So basically the problem is:
If I am deleting DOM Elements of a WebComponent (so deleting the CustomElement itself) from external, and then re-adding it with another route, The Child-route components of this will not get loaded. If there is a short delay (50ms), everything works fine.
To reproduce the problem:
Load page and click an the "switch with delay" button.
Reveal Detail Component
Switch to the other Overview by clicking "switch with delay" again.
Reveal Detail Component
=> Everything should work fine
Repeat the same steps, but this time click only on "switch directly".
Prior Investigations
What I already debugged is the Router. So I went through the log messages with "enable tracing"
and they seemed to be no differences. Afterwards I compared the Components' Lifecycle and
the thing I noticed is, that in the working example the old Detail**1**Component Object will get destroyed a new Detail**1**Component one will be created and directly destroyed afterwards and then everything regarding the Detail**2**Component will get constructed.
On the not working example it is like this:
A new Detail**1**Component will get constructed again and destroyed afterwards. Then the old Detail**1**Component will get destroyed. Then nothing regard the Detail**2**Component will get constructed.
So routing seems to work fine, but components won't get loaded in this case, maybe due to a strange lifecycle, because of the Detachment of the View to the ViewModel happening due to hard deleting those WebComponent in DOM.
Maybe I am just dumb and did something fundamentally wrong, but I could not find anything in the Web regarding this problem and every solution I tried by myself just resulted in a workaround like establishing a delay.
You can find a workaround available on Github.
I forced the recreation of the DOM object by attaching a boolean
to the navigation button, which will determine if the DetailComponent
should actually get shown.
<router-outlet *ngIf="shown">
Then the Outlet will get reevaluated and the DOM will get refilled on clicking the button.
This will effectively mitgating the issues described.
In my opinion its not the cleanest solution, but cleaner than a timeout, that
even needs to get applied from the outside.
I hope this was helpful and maybe someone might point me to the actual fix and
not only workaround.
Since this was my first question do not hesitate to give me feedback on formal
appearance.

How can I delete a block that contains faulty JavaScript breaking the C5 interface?

I was working on an HTML block in Concrete5 located in the footer. I made a javascript call - can't quite remember it, but I think it was referencing either jQuery or the Google Maps API. Anyway, now the block won't display and oddly enough, I am completely unable to modify/add/remove blocks now. I'm pretty sure it is because of the javascript call it is making, but I can't modify or delete the block to fix the issue.
What am I supposed to now? I tried disabling javascript in my browser but of course that won't let me modify the blocks either.
I don't know 5.8+ that well yet, but this may be unfixable from within the UI.
If the error is in a global area, your best bet might be opening the template, changing the area name where the global area is used and displayed, and recreating it from scratch.
You'd be looking for something like this:
$a = new GlobalArea("Footer Nav");
and change the global area's name, thus creating a new one.
If that's not an option, you may have to resort to deleting (or altering) the faulty block through the API.
In my experience, the easiest way to get a blank page that has C5 bootstrapped is creating a custom Dashboard page:
It's a common task for a Concrete5 developer to create their own Dashboard pages. Dashboard pages are just single pages located inside the "single_pages/dashboard" directory. Once they're added within that location, they automatically show up in the Dashboard.
Now, as to how to edit or delete the block inside the area, I don't have a complete recipe, but this example page showing advanced area operations should get you started.
The API documentation for GlobalAreas is here, for Block here (notice the delete() / deleteBlock() methods.)
FYI although the solution marked as best works, it leaves data in the database that will stay there forever and forces you to change your area's name which might be ok once but not if it happens again and again.
Since that was an HTML block, the best way was to go to your database's interface, probably phpMyAdmin, go into the table "btContentLocal" and do a search for the faulty code you had entered in the HTML block then fix or delete it.
Like that you're back to normal, you don't leave stuff behind, and you can keep your area as it is

Removing Reactjs Om components (ClojureScript)

I am trying to make a tabbed windowing system within a webpage using om-bootstrap's "pills" navigation by adding tabs when links get clicked and removing tabs when an X button on the tabs is clicked.
I need to know how to add and remove data from the global state/store and create a macro that can be used to declare a tab app component and make it remove itself when it is no longer alive.
What is the best way to reference the global state? How can I make a component remove/unmount itself when it gets closed?
Since removal of a subcomponent affects its owner, you should let the owner (i. e. the "tab system") know that this tab needs to be closed/destroyed/obliterated.
I've digged through todomvc example (live) assuming your process of destroying tab panes is pretty much the same as destruction of TODO items there. I see nothing ocnflicting so far. Here are my findings:
A channel is used.... When application starts (IWillMount), a (chan) (from core.async) is written into application state at :comm key.
...for event handling.... Events from the channel are handled in the loop following that code, in go-form, asynchronously with the block it appears in (with <! being a "kinda blocking" operation). Well, you may know it, I didn't, still learning what is CLJS all about.
...that is passed to all child items' init states.... So it becomes a way for children to send events to the root. I'm starting to like this.
...so they can send events to their parent! This is done in put! calls with the comm channel, fetched in the linked line. Events put there are handled by the loop defined in (2), which delegates them to appropriate functions depending on type (accompanying keyword).
I'm nowhere near a ClojureScript pro, but I'm learning. So if the above doesn't make sense, this is normal and means I didn't understand something. If that turns out to be the case, putting me back on track would be much appreciated.

How do I find what Javascript is running on certain events?

I'll pick Chrome for this example, but I'm open to a solution from any browser.
Use Case:
I have an update button on my website that is used to update item quantities in a shopping cart. I'd like to allow a user to enter a 0 and click update in order to remove the item. Trouble is, there is some listener in some js function that is denying the ability to enter a 0 and click update (after clicking update the old quantity remains).
My question is, what developer tool can I use to find which js function is running during that event? I don't think that Chrome's inspector does this, and I'm not very familiar with Firebug, but I couldn't find the functionality there either.
I feel that I should be able to inspect js firings just like I do css stylings. Is anyone aware of a tool I may use?
I've had to debug some particularly nasty unseen-cause Javascript issues at my job. Knowing the full depth of developer tools like Chrome's is definitely helpful. It undeniably takes some creativity to find places that might be causing the issue, but a few tips:
Tracking down event listeners
Under Chrome's Elements view, try Inspect-ing an element (right-click, Inspect); then, on the right side of the developer view, scroll down to Event Listeners. Here you can view what code files have hooked up an event. Often, this will just point you to a middle-framework from the really devious code you're looking for, but sometimes it will point you in the right direction.
Trapping a DOM modification
Many of the unwanted effects I see are because of something changing some value or attribute on the page that I don't want. Anytime this happens, you can right-click on the element (under the Elements view) and say "Break on..." and the specific scenario you're looking for. When Chrome then hits a breakpoint, you can then look downward in the Stack Trace until you find something recognizable that shouldn't be called.
EDIT after reaching ten votes!
Trapping a JS object modification
If the change you're interested in is code-internal, not in the UI, things get trickier. What's meant by this scenario is that you know somewhere in the code, something incredibly annoying like the following is happening.
company.data.myObject.parameter = undefined;
In this situation, you know myObject is still the same object, but it's being modified, perhaps unintentionally. For that, I often insert the following bit of code, sometimes just through the developer console at some point before said modification happens.
Object.defineProperty(company.data.myObject, 'parameter', {
set: (val) => {
debugger;
}
});
This includes an arrow function - you're only using this for debugging and Chrome supports it, so might as well save keystrokes. What this will do is freeze your debugger as soon as some line of code attempts to modify myObject's "parameter" property. You don't necessarily have to have a global reference to the variable if you can run this line of code from a previous breakpoint that will have the given object in the locals.
Otherwise, if all I'm starting out with is the HTML code, and I want to tie that to Javascript code, I'll often just look for identifying features like "id" elements, and search all JS files in my development directory for it. Normally, I can reach it pretty fast.
Open your page in Firefox with Firebug enabled.
Go to console tab in firebug and click profiling
enter 0 in the textbox and click the button.
Stop profiling.
You will be able to see all the javascript functions which have executed due to your actions. You can view them one by one to figure out which method has caused the mischief.
Go to you code. If you are using jQuery there is going to be a function that will be called with the class or id of that particular update button. Or, if you are using Javascript, there is going to be a function called inside the
<input type="button" name="update" onclick="update()">
These are the two ways to look for the function that is being called; there is no software that I know
Download Firebug for Mozilla Firefox, open it, click on Net and refresh your website. Than, you can see which files are loaded on the page.
If you want to check on errors and what goes wrong with an explanation, than click on console and refresh the page once again. You will see the errors and on which line it goes wrong.
Note: in your console, you can say hold or stop, so that the js file stops loading. And you can edit the script by clicking on script in Firebug. Debugging is simple, as it says on their official page https://getfirebug.com/javascript

Multiple Dashboard widget instances don't survive widget update. Any way to prevent this?

I've written a Mac OS X Dashboard to show the StackOverflow flair of yourself and other people.
My problem is that whenever I update that widget to a new version, all previous instances are removed and a single new instance is created on the Dashboard. So if you previously followed the flair of 4 people you'll have to recreate the widgets and enter their user-IDs again. :(
Is there any way to keep all running instances while updating a widget?
Checking the preferences file, I see that a new instance is created after a new version of the widget is deployed. Is this by design? Does all widgets work like this, by any chance?? If so, can this be manually circumvented somehow?
You can find the widget in question, including the project files, at http://widget.huxhorn.de
I've changed the code in remove() to set the preferences to the correct values instead of null as suggested below - but this doesn't help, either.
What's my mistake?? Help! I'm stuck!
The other problem of my widget has been fixed:
I accidentally called
widget.preferenceForKey(null, dashcode.createInstancePreferenceKey(userIdPrefKey));
instead of
widget.preferenceForKey(dashcode.createInstancePreferenceKey(userIdPrefKey));
but this is now fixed (not yet released).
I know about this tool that takes over the install process: http://junecloud.com/software/mac/smart-widget-installer.html
(source: junecloud.com)
I think your calls to setPreferenceForKey and preferenceForKey look strange. Where does that null come from. Shouldn't they look like
widget.preferenceForKey(dashcode.createInstancePreferenceKey(userIdPrefKey))
widget.setPreferenceForKey(value, dashcode.createInstancePreferenceKey(userIdPrefKey));
Does the syntax with null
widget.setPreferenceForKey(null, dashcode.createInstancePreferenceKey(userIdPrefKey))
in remove() delete the preference? That would explain you situation I guess. On Update the remove() gets surley called and thus on restart of the widget the preferences are gone.
I guess there is only one way to keep your preferences during an update. Create one preferencekey without relying on dashboard.createInstancePreferenceKey but instead think yourself of a unique key value.
In this preferenceKey you could then save all ever entered userids (by any instance) with a growing (say comma seperated) list. When a widget instance is opened an the widget.preferenceForKey(dashcode.createInstancePreferenceKey(userIdPrefKey)) isn't already set you could let the user choose one of those by giving him a select or such a thing
I was just thinking maybe the update process is nice enough to migrate the preferences to the new verison. Even when you don't remove the preferences I think the widget.identifier (createInstancePreferenceKey) will have changed an thus you can't access the "old" settings.

Categories

Resources