Highlighting current selected textfield - best approach - javascript

I am trying to achieve an effect like this on mobile (ios + android):
http://i.imgur.com/6zaTdRd.png
Where the currently selected textfield has a blue tinted icon + underlining
So my framework lacks any support for grey scaling a bitmap image of any sort so I need to swap between two images to achieve this effect.
My current implementation looks like this:
Please note this for the Titanium Alloy MVC framework but I'm guessing the basic logic should be similar.
I listen for blur/focus events to toggle current image
$.firstNameField.addEventListener('focus', function(e){
swapImages($.firstNameField.getParent());
});
$.lastNameField.addEventListener('focus', function(e){
swapImages($.lastNameField.getParent());
});
and then I swap images like so:
/**
* Swaps between the images (..._0 and ..._1) of an ImageView nested in a
TableRow
* ..._0 Greyscale image
* ..._0 Colour image
* #param e current TableViewRow
*/
function swapImages(e){
var imagePathSplit = (e.children[0].image).split('_');
var newImagePath = null;
if(imagePathSplit[1] == "0.png")
newImagePath = imagePathSplit[0] + "_1.png";
else
newImagePath = imagePathSplit[0] + "_0.png";
e.children[0].image = newImagePath;
return;
}
This doesn't look that great especially since I need a lot more fields with this functionality, I also want to implement tabbing (using Return key = NEXT) between the fields which will further balloon to increase 1 more event listener per field.
How would something like this be done ideally? I can think of one way of just creating the fields in code in array form which should help simplify matters (no more looking too far for Parent/Children, but that would still end up using quite a bit of listeners for switching right?
EDIT: Forgot to add how I have the textFields setup:
<TableView id="paypalTable">
<TableViewSection>
<TableViewRow id="firstNameView" class="tableRow">
<ImageView id="firstNameIcon" class="textFieldIcon"/>
<TextField id="firstNameField" class="textField"/>
</TableViewRow>

I tried something similar in one of my projects. Although I had an Alloy project I had to use a classic approach to get my desired behaviour.
In my controller:
var textFields = [];
var yourTextFieldsArray = [];
for (var i = 0; i < yourTextFieldsArray; i++) {
//Set the selected state to false initially. Maybe you need another command for it.
textFieldIsSelected[i] = false;
//create your new view
textFields[i] = Ti.UI.createView({
top : topValues[i],
width : Titanium.UI.FILL,
height : height,
id : i + 1,
touchEnabled : true
});
textFields[i].addEventListener('click', function(e) {
//Check the source id
if (e.source.id - 1 > -1) {
//use your function swapImages(e.source.id). Notice the slightly different parameter since you do not need the complete event.
swapImages(e.source.id);
}
}
function swapImages(id){
//Check the the path variable as you did
var imagePathSplit = (textFields[i-1].image).split('_');
var newImagePath = null;
if(imagePathSplit[1] == "0.png")
newImagePath = imagePathSplit[0] + "_1.png";
else
newImagePath = imagePathSplit[0] + "_0.png";
textFields[i-1].image = newImagePath;
}
This approach lets you use the same event listener for every property.
Please notice that my ids start at 1 and not at 0. This is because I had to implement such a behaviour for images and ImageViews do not accept id=0. My guess is that TextViews don't do it either so you should stick with it. Further notice that you need to decrement the id to get the corresponding object in the textFields Array. Otherwise you would get an out of bounds error.
You should create one more event listener for your NEXT event. Implement it in the same way as the first eventListener. Maybe the code is not perfect because I wrote it from my memory. If there are any questions left feel free to ask in the comments.

Related

multiple kendo grids using one script

I'm loading multiple partial views into the same cshtml page. All goes well until they need to use the scripts. As i'm using code like
var grid = $("#grid").data("kendoGrid");
var selected = grid.selected();
This code works fine with one grid, but starts showing issues when multiple grids are in place. The problem is that "#grid" is a reference to the name of the kendo grid. Is there a way to make this dynamic so it can be used by multiple grids?
I think the same problem would occur when there are multiple grids in the same page as it can't distinct what grid to refer to. Giving the grids different id's would work, but then the code in the script will return an undefined error on grid.selected().
Update:
So the solution of using
var grid = $(".k-grid").data("kendoGrid");
works to a certain point. It loads the data into the grid, but fails to do anything else. For example a part of my code for enabling an update and delete button doesn't work on the 2nd and 3rd partial view.
var grid = $(".k-grid").data("kendoGrid");
var selected = grid.select();
if (selected.length > 0) {
$("#btnCopy,#btnEdit,#btnDelete").removeClass("k-state-disabled");
} else {
$("#btnCopy,#btnEdit,#btnDelete").addClass("k-state-disabled");
}
Somehow the code only starts working for grid 2 and 3 after i have selected a row on grid 1, which is not as intended.
Instead of id(#Grid) you can use class(.k-grid):
var grid = $(".k-grid").data("kendoGrid");
The solution I found with help of a senior programmer is to save the grid data into a global variable like this.
var PartialGridData = PartialGridData || {};
After that I'm setting and changing the variable whenever changing the partial view.
PartialGridData.selectedGrid = $("#PartialGrid1").data("kendoGrid");
Where the name #PartialGrid1 is the name of the current grid.
This means I need to write this code as many times as I have grids, but it also fixes a lot of problems. After that I use it to select the correct data.
var grid = PartialGridData.selectedGrid;
var selected = grid.select();
if (selected.length > 0) {
$("#btnCopy,#btnEdit,#btnDelete").removeClass("k-state-disabled");
} else {
$("#btnCopy,#btnEdit,#btnDelete").addClass("k-state-disabled");
}
Another option would be to use e.sender.
function onRowSelect(e) {
var grid = e.sender;
var selected = grid.select();
if (selected.length > 0) {
$("#btnCopy,#btnEdit,#btnDelete").removeClass("k-state-disabled");
} else {
$("#btnCopy,#btnEdit,#btnDelete").addClass("k-state-disabled");
}
}
Both solutions have their drawbacks though. Not all methods get the variable e used for e.sender and changing partial views in a way that is not caught will cause the global variable not to be updated, so this has to be kept in check.

Disable view picker DIV is not accessible in MS CRM

I am trying to disable view picker on account lookup in 2016.
The code works fine I mean I am not getting any error but the code not able to find the particular DIV of "parentaccountid".
Where as I can see it in Elements:
But it's returns {null} when the code try to get the elements of DIV - document.getElementByid("parentaccountid");
My code runs on load of opportunity page.
Even at this step I can see the particular DIV element- id: parentaccountid
Where as I still get {null} value:
Where as in 2013 I have seen it working pretty fine.
Sorry I don't have data to share here but it works fine.
Here is the code below:
function DisablePick()
{
VULoader();
//call this function from OnLoad handler
function VULoader(){
var myLookup1;
alert("Hello..I am Here");
var fetch = "<fetch mapping='logical'>"
+"<entity name='account'>"
+"<attribute name='name'/>"
+"<filter type='and'>"
+"<condition attribute='name' operator='eq' value='Blue Yonder Airlines (sample)' />"
+"</filter>"
+"</link-entity>"
+"</entity>"
+"</fetch>";
myLookup1 = new XrmLookupField("parentaccountid");
myLookup1.AddLockedView(
//sViewId
myLookup1.NewGuid() ,
//sEntityName
"account",
//sViewDisplayName
"My Locked Custom View",
//sFilterXml
fetch,
//sFilterLayout
layout(1, "name", "accountid")
.column("name", 200)
.toString()
);
}
function XrmLookupField(sId) {
var xlf = this;
//control instance
xlf.Ctl = Xrm.Page.getControl(sId);
//dom instance
xlf.Dom = document.getElementById(sId);
//jquery instance
xlf.$ = $(xlf.Dom);
/* 2013 addition --- Inline Control instance --- */
xlf.$i = $("#" + sId + "_i");
//use that to disable the view picker
xlf.DisableViewPicker = function () {
/* 2013 addition --- The attribute capitalization changed */
xlf.SetParameter("disableviewpicker", "1");
}
//use that to enable the view picker
xlf.EnableViewPicker = function () {
/* 2013 addition --- The attribute capitalization changed */
xlf.SetParameter("disableviewpicker", "0");
}
//set undocumented attributes
xlf.SetParameter = function (sName, vValue) {
xlf.$.attr(sName, vValue);
/* 2013 addition --- Also change the inline contorl value */
xlf.$i.attr(sName, vValue);
}
//add locked view
xlf.AddLockedView = function (sViewId, sEntityName, sViewDisplayName, sFilterXml, sFilterLayout) {
//first enable the view picker
xlf.EnableViewPicker();
//add the custom view (last parameter set the view as default)
xlf.Ctl.addCustomView(sViewId, sEntityName, sViewDisplayName, sFilterXml, sFilterLayout, true);
//lock the view picker
xlf.DisableViewPicker();
}
//create new guid
xlf.NewGuid = function () {
var d = new Date().getTime();
var guid = '{xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx}'.replace(/[xy]/g, function (c) {
var r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16);
});
return guid;
}
}
}
Few points to mention:
I am calling DisablePicker method on load of an opportunity page.
Yes, I have already checked whether any duplicate id is there or not but I didn't find any.
I tried to run this method on load of Account field as well but nope no response.
If I change the property disableviewpicker value from 0 to 1 in DIV itself manually from browser after page gets loaded & open the lookup then it will take the effect of the changed value.
Really I am getting no clue why it's behaving this manner, I just need to know where exactly I am going wrong or it's a product bug but I don't think it is. As its a very basic behavior.
PS: For my non MS CRM friends I cannot change the DIV or anything except my JavaScript code.
Your form code executes in a frame that is separate from the actual CRM form; it runs in the ClientApiWrapper.aspx page. Therefore, to access the form element you want to modify from your form script, you form code should do parent.document.getElementById instead of document.getElementById.
When you use your browser's dev tools, the default frame that the console executes against is also not the frame that has your form elements, and it's also not the frame that has your form's code. The simplest way to execute against the correct frame is to use the function in your dev tools to switch frames. In Firefox, that button looks like this:
It's easiest to set your frame to the ClientApiWrapper.aspx one, as it provides access to both the libraries loaded on your form as well as the CRM client-side API.

Synchronize interdependent Dojo widgets/values

I'm about to build a simple "mortgage calculator" where a user is to adjust some sliders OR edit values in input fields in order to calculate some final value based on the provided data.
Schematically it will look something like this:
Slider1 - Input1
Slider2a - Input2a
Slider2b - Input2b
The idea is that the value of the input must be reflected in the slider, and vice versa. In addition, the values and limits of slider 2a/2b and input 2a/2b depend on each other, according to some simple rule.
It has to be done in Dojo, which I've never used before, and, even though Dojo has quite good documentation, it is a little overwhelming, so I'd appreciate if someone could point me in the right direction.
First of all, here is my solution working at jsFiddle: http://jsfiddle.net/phusick/HCx3w/
You can use dojo/aspect, dojo/topic and dojo/Stateful and directly connect those widgets to each other in various ways. You will probably end up with a tightly coupled set of widgets, i.e. those widgets will know about each other, even if there is no reason a particular widget should have any knowledge about the fact its value is being synchronized with another widget.
Contrary to the aforementioned you can apply loose coupling principle, which will allow you to synchronize any number of widgets without any mutual references among them. Here is my solution:
Obtain references to widgets and couple them into sets (arrays):
var slider1 = registry.byId("slider1");
var slider2 = registry.byId("slider2");
var spinner1 = registry.byId("spinner1");
var spinner2 = registry.byId("spinner2");
var set1 = [slider1, spinner1];
var set2 = [slider2, spinner2];
synchronize function:
var synchronize = function(/*Array*/ widgets, /*String*/ topicName) {
var synchronized = function() {
var count = 0;
array.forEach(widgets, function(widget) {
if(widget.get("synchronized") === true) { count++}
});
return (count == widgets.length);
}
array.forEach(widgets, function(w) {
w.set("synchronized", false);
// register onchange handler for each widget in the set
w.on("change", function(value) {
array.forEach(widgets, function(widget) {
if(this !== widget) {
widget.set("value", value);
widget.set("synchronized", true);
}
}, this);
// needed to publish topic just once per value change across all the widgets in the set
if(synchronized()) {
array.forEach(widgets, function(widget) {
widget.set("synchronized", false);
});
// publish topic if any
if(topicName) { topic.publish(topicName, value)};
}
});
});
}
Register sets of widgets to synchronize via sychronize function:
synchronize(set1, "value1-changed"); // synchronize and publish topic when value changes
synchronize(set2); // just synchronize
Subscribe to the topic you registered above:
topic.subscribe("value1-changed", function(value) {
console.log("value1-changed", value);
// here you can change value and limits of of `set2` widgets
});
dojo. Stateful is your friend... http://dojotoolkit.org/reference-guide/1.7/dojo/Stateful.html
Have you tried dojo.connect. This can be used method chaining. So when the event is fired in control multiple methods can be invoked. Beside this there is publish\subscribe mechanism in dojo. In pub\sum model you can write method to subscribe for simple message strings. When some method published that string, than subscriber method will be invoked.

onClick replace /segment/ of img src path with one of number of values

No idea what I'm doing or why it isn't working. Clearly not using the right method and probably won't use the right language to explain the problem..
Photogallery... Trying to have a single html page... it has links to images... buttons on the page 'aim to' modify the path to the images by finding the name currently in the path and replacing it with the name of the gallery corresponding to the button the user clicked on...
example:
GALLERY2go : function(e) {
if(GalleryID!="landscapes")
{
var find = ''+ findGalleryID()+'';
var repl = "landscapes";
var page = document.body.innerHTML;
while (page.indexOf(find) >= 0) {
var i = page.indexOf(find);
var j = find.length;
page = page.substr(0,i) + repl + page.substr(i+j);
document.body.innerHTML = page;
var GalleryID = "landscapes";
}
}
},
There's a function higher up the page to get var find to take the value of var GalleryID:
var GalleryID = "portfolio";
function findGalleryID() {
return GalleryID
}
Clearly the first varGalleryID is global (t'was there to set a default value should I have been able to find a way of referring to it onLoad) and the one inside the function is cleared at the end of the function (I've read that much). But I don't know what any of this means.
The code, given its frailties or otherwise ridiculousness, actually does change all of the image links (and absolutely everything else called "portfolio") in the html page - hence "portfolio" becomes "landscapes"... the path to the images changes and they all update... As a JavaScript beginner I was pretty chuffed to see it worked. But you can't click on another gallery button because it's stuck in a loop of some sort. In fact, after you click the button you can't click on anything else and all of the rest of the JavaScript functionality is buggered. Perhaps I've introduced some kind of loop it never exits. If you click on portfolio when you're in portfolio you crash the browser! Anyway I'm well aware that 'my cobbled together solution' is not how it would be done by someone with any experience in writing code. They'd probably use something else with a different name that takes another lifetime to learn. I don't think I can use getElement by and refer to the class/id name and parse the filename [using lots of words I don't at all understand] because of the implications on the other parts of the script. I've tried using a div wrapper and code to launch a child html doc and that come in without disposing of the existing content or talking to the stylesheet. I'm bloody lost and don't even know where to start looking next.
The point is... And here's a plea... If any of you do reply, I fear you will reply without the making the assumption that you're talking to someone who really hasn't got a clue what AJAX and JQuery and PHP are... I have searched forums; I don't understand them. Please bear that in mind.
I'll take a stab at updating your function a bit. I recognize that a critique of the code as it stands probably won't help you solve your problem.
var currentGallery = 'landscape';
function ChangeGallery(name) {
var imgs = document.getElementsByTagName("img") // get all the img tags on the page
for (var i = 0; i < imgs.length; i++) { // loop through them
if (imgs[i].src.indexOf(currentGallery) >= 0) { // if this img tag's src contains the current gallery
imgs[i].src = imgs[i].src.replace(currentGallery, name);
}
}
currentGallery = name;
}
As to why I've done what I've done - you're correct in that the scope of the variables - whether the whole page, or only the given function, knows about it, is mixed in your given code. However, another potential problem is that if you replace everything in the html that says 'landscape' with 'portfolio', it could potentially change non-images. This code only finds images, and then replaces the src only if it contains the given keyword.

change some tinymce behaviour (javascript)

Hi everybody
I am using the tinymce format dropdown to apply custom styles to html elements. This is for users without html knowledge
One annoying thing for me is that when a user klicks at different styles they all get added and something like this may happen
<div class="floatleft floatright positionup positiondown">
In order to prevent this I searched for the responsible code which is in editor_template.js (compressed) but visible in editor_template_src.js
Is there maybe a way to rewrite this piece of javascript so that each applied style replaces the former?
_createStyleSelect : function(n) {
var t = this, ed = t.editor, ctrlMan = ed.controlManager, ctrl;
// Setup style select box
ctrl = ctrlMan.createListBox('styleselect', {
title : 'advanced.style_select',
onselect : function(name) {
var matches, formatNames = [];
each(ctrl.items, function(item) {
formatNames.push(item.value);
});
ed.focus();
ed.undoManager.add();
// Toggle off the current format
matches = ed.formatter.matchAll(formatNames);
if (!name || matches[0] == name)
ed.formatter.remove(matches[0]);
else
ed.formatter.apply(name);
ed.undoManager.add();
ed.nodeChanged();
return false; // No auto select
}
});
How about:
if (!name || matches[0] == name)
ed.formatter.remove(matches[0]);
else
ed.formatter.remove(matches[0]);
ed.formatter.apply(name);
Just a wild guess, haven't tried it myself.
This a lot of work to do, but it can be done.
I solved this issue writing a custom plugin and using a custom FormatterClass.
I suggest you try developing with tiny_mce_dev.js - this way you are able to track down problems to js classes.
Then you should have a look at the js-class Formatter.js and try to modify this one in order to fullfill your wishes.
The next step will be to save the mofied Formatter.js and make it part of your plugin, so that you can reset the real Formatter.js, cause i suggest not to change the tinymce core files.

Categories