jQuery Mobile Google Universal Analytics - jquery-mobile

I've been happily using this best practice http://roughlybrilliant.com/jquery_mobile_best_practices#7 for integrating ga.js with jQuery Mobile. I'm planning to upgrade to analytics.js using the new Universal Analytics tracking code. I wonder whether something like this below will work following the best practice using the ga.js tracking code.
<script>
$(document).ready(function (e) {
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o),
m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
});
$(document).on('pageshow', '[data-role=page], [data-role=dialog]', function (event, ui) {
try {
ga('create', 'UA-XXXXXXXX-X', 'domain.com');
if ($.mobile.activePage.attr("data-url")) {
ga('send', 'pageview', '$.mobile.activePage.attr("data-url")');
} else {
ga('send', 'pageview');
}
} catch (err) {}
});
</script>

Everything should work above save the '$.mobile...' part being in quotes. A few of their suggestions are a bit off though. Refractored below
<script>
// domReady is unnecessary here and can slow down perceived performance
// $(document).ready(function (e) {
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o),
m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-XXXXXXXX-X', 'domain.com'); // move this here!
// });
$(document).on('pageshow', '[data-role=page], [data-role=dialog]', function (event, ui) {
try {
if ($.mobile.activePage.attr("data-url")) {
ga('send', 'pageview', $.mobile.activePage.attr("data-url")); // remove quotes
} else {
ga('send', 'pageview');
}
} catch (err) {}
});
</script>

Related

Google Analytics based on Microsoft.AspNet.Identity roles

I am trying to find a way to register all the traffic of a website with Google Analytics, spliting the reporting based on the Microsoft.AspNet.Identity role.
I did not found anything that allows to do it.
Something like:
if(User.IsInRole("public"))
{
<script>
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date(); a = s.createElement(o),
m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', 'PUBLIC', 'auto');
ga('send', 'pageview');
</script>
}
else if (User.IsInRole("private"))
{
<script>
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date(); a = s.createElement(o),
m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', 'PRIVATE', 'auto');
ga('send', 'pageview');
</script>
}
You are looking for the User ID feature. Here is a Tutorial.
You need to setup the feature. Then you can start tracking like this:
ga('create', 'UA-XXXXXX-Y', {'userId': customUserId});
Anonymous Users you can detect by
User.Identity.IsAuthenticated
You want to send a userid that you do not have like 0 for anonymous users.
I have been testing for a few days now and I found a great way to have 2 different properties in the same account:
#if (Model.IsUserInternal == true)
{
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-XXXXXXXXX-2', 'auto');
ga('send', 'pageview');
</script>
}
else
{
<script>
(function(i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function() {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date(); a = s.createElement(o),
m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-XXXXXXXXX-1', 'auto');
ga('send', 'pageview');
</script>
}
Where XXXXXXXXX is the same.

CKEditor not working after opening jQuery UI Dialog

I have a jQuery UI Dialog that has a CKEditor instance on it. I can open the dialog and interact fine with the editor. But if I open another jQuery UI dialog from the original dialog the text in the editor disappears when the second dialog opens and the editor can't be used until you reload the entire page.
This works fine if the CKEditor instance is not in a dialog. I can open up the child dialog, use it, close it, and still interact with editor.
Any ideas what is going on and how to make it work?
Sample program below or http://jsfiddle.net/3EyM4/1/
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/ckeditor/4.3.2/ckeditor.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/ckeditor/4.3.2/adapters/jquery.js"></script>
</head>
<body>
<script>
$(document).ready(
function()
{
$('textarea').ckeditor( { toolbar: [] } );
$( "#childDialog" ).dialog(
{
autoOpen: false
} );
$( "#parentDialog" ).dialog(
{
autoOpen: false
} );
});
</script>
<div>
Main page
<button onclick="$('#parentDialog').dialog( 'open' );">Open Parent</button>
</div>
<div id="parentDialog" title="Parent Dialog">
<button onclick="$('#childDialog').dialog( 'open' );">Open Child</button>
<textarea name="editorTextArea"></textarea>
</div>
<div id="childDialog" title="Child Dialog">
Child
</div>
</body>
</html>
You need to instantiate the CKEDITOR on the open event of the dialog
open: CKEDITOR.replace('editor1', {
height: 145,
width: 500,
allowedContent: true,
}),
Then is will allow text. Something to do with the Iframe that CKEDITOR uses
This will work fine
Check CKEditor intances than destroy it when dialog is closed. Enjoy your code
function DestryoCKEditorInstances(textarea_name)
{
if (CKEDITOR.instances[textarea_name])
{
CKEDITOR.instances[textarea_name].destroy();
}
}
$( "#add-task" ).dialog({
modal: true,
minHeight: 600,
minWidth: 600,
position: [0,28],
create: function (event) { $(event.target).parent().css('position', 'fixed');},
open: CKEDITOR.replace('textarea_name',{language: 'tr',height: 150,width: 550, allowedContent: true}),
close: function (){
DestryoCKEditorInstances('textarea_name');
form[ 0 ].reset();
},
buttons: {
"Add Task": function() {
Add();
form[ 0 ].reset();
$( this ).dialog( "close" );
},
"Keep Going To Add Task": function() {
Add();
form[ 0 ].reset();
},
Cancel: function() {
form[ 0 ].reset();
$( this ).dialog( "close" );
}
}
});
I found a workaround at least. If I save the contents of the editor and destroy the instance before opening the dialog, and then recreate the editor instance after opening the dialog, it all works fine.
var editor = $('textarea').ckeditorGet();
editor.updateElement();
editor.destroy();
$('#childDialog').dialog( 'open' );
$('textarea').ckeditor( { toolbar: [] } );
I had a similar problem loading text into ckeditor while it was inside a jquery ui dialog. I had 2 instances of ckeditor and an ajax post to get the data so my workaround was:
(...)
success: function(data, textStatus, jqXHR) {
for (name in CKEDITOR.instances) {
CKEDITOR.instances[name].destroy()
}
$('#newForm').dialog('open');
$("#dialog").focus();
$('#txtDescription').ckeditor({ toolbar: 'Basic' });
$('#txtDescriptionFr').ckeditor({ toolbar: 'Basic' });
CKEDITOR.instances['txtDescription'].setData(data.Description.NameEn);
CKEDITOR.instances['txtDescriptionFr'].setData(data.Description.NameFr);
}
To get around the Problems when having a CKEDITOR in a Jquery ui-dialog I did the following:
Problem 1:
Dropdowns like font-size etc. arent visible in ckeditor.
Solution:
config.baseFloatZIndex=9999999;
Problem 2:
Input Fileds in CKEDITOR Dialog arent "active".
Solution:
Close ui-dialog when ckeditor dialog opens and vice-versa
Problem 3:
Ckeditor dialog input fields arent "active" when ckeditor switches to fullscreen mode
Solution:
Close jquery ui-dialog when ckeditor is going to fullscreen, reopen when leaving fullscreen mode
My CKEDITOR jquery adapter now looks like this, works fine for me:
/*
Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.md or http://ckeditor.com/license
*/
(function(a) {
if ("undefined" == typeof a) throw Error("jQuery should be loaded before CKEditor jQuery adapter.");
if ("undefined" == typeof CKEDITOR) throw Error("CKEditor should be loaded before CKEditor jQuery adapter.");
console.error("CKEDITOR jQuery Team-pro adapter v0.4a");
CKEDITOR.config.jqueryOverrideVal = "undefined" == typeof CKEDITOR.config.jqueryOverrideVal ? !0 : CKEDITOR.config.jqueryOverrideVal;
a.extend(a.fn, {
ckeditorGet: function() {
var a = this.eq(0).data("ckeditorInstance");
if (!a) throw "CKEditor is not initialized yet, use ckeditor() with a callback.";
return a
},
ckeditor: function(g, d) {
if (!CKEDITOR.env.isCompatible) throw Error("The environment is incompatible.");
if (!a.isFunction(g)) {
var m = d;
d = g;
g = m
}
var k = [];
d = d || {};
this.each(function() {
var b = a(this),
c = b.data("ckeditorInstance"),
f = b.data("_ckeditorInstanceLock"),
h = this,
l = new a.Deferred;
k.push(l.promise());
if (c && !f) g && g.apply(c, [this]), l.resolve();
else if (f) c.once("instanceReady", function() {
setTimeout(function() {
c.element ? (c.element.$ == h && g && g.apply(c, [h]), l.resolve()) : setTimeout(arguments.callee, 100)
}, 0)
},
null, null, 9999);
else {
if (d.autoUpdateElement || "undefined" == typeof d.autoUpdateElement && CKEDITOR.config.autoUpdateElement) d.autoUpdateElementJquery = !0;
d.autoUpdateElement = !1;
b.data("_ckeditorInstanceLock", !0);
c = a(this).is("textarea") ? CKEDITOR.replace(h, d) : CKEDITOR.inline(h, d);
b.data("ckeditorInstance", c);
c.on("instanceReady", function(d) {
var e = d.editor;
e.config.baseFloatZIndex=9999999;
setTimeout(function() {
if (e.element) {
d.removeListener();
e.on("dataReady", function() {
b.trigger("dataReady.ckeditor", [e])
});
e.on("setData", function(a) {
b.trigger("setData.ckeditor", [e, a.data])
});
e.on("getData", function(a) {
b.trigger("getData.ckeditor", [e, a.data])
}, 999);
e.on("destroy", function() {
b.trigger("destroy.ckeditor", [e])
});
e.on("save", function() {
a(h.form).submit();
return !1
}, null, null, 20);
if (e.config.autoUpdateElementJquery && b.is("textarea") && a(h.form).length) {
var c = function() {
b.ckeditor(function() {
e.updateElement()
})
};
a(h.form).submit(c);
a(h.form).bind("form-pre-serialize", c);
b.bind("destroy.ckeditor", function() {
a(h.form).unbind("submit", c);
a(h.form).unbind("form-pre-serialize",
c)
})
}
e.on("destroy", function() {
b.removeData("ckeditorInstance")
});
/*
e.on("maximize", function (e) {
// console.log('---------------------------- MAXIMIZE ----------------------------');
// console.debug(e.data);
switch(parseInt(e.data)){
case(1)://Gehe in Fullscreen, SCHLIESSE Jquery ui Dialoge
console.log('CKEDITOR [maximize:true] jQuery adapter: schliesse ui-dialog');
$('.ui-dialog-content').dialog('close');
break;
case(2)://Gehe in Fullscreen, OFFNE Jquery ui Dialoge
console.log('CKEDITOR [maximize:false] jQuery adapter: öffne ui-dialog');
$('.ui-dialog-content').dialog('open');
break;
}
});
*/
b.removeData("_ckeditorInstanceLock");
b.trigger("instanceReady.ckeditor", [e]);
g && g.apply(e, [h]);
l.resolve()
} else setTimeout(arguments.callee, 100)
}, 0)
}, null, null, 9999)
}
});
var f = new a.Deferred;
this.promise = f.promise();
a.when.apply(this, k).then(function() {
f.resolve();
CKEDITOR.on("dialogDefinition", function (e) {
var dialogName = e.data.name;
var dialog = e.data.definition.dialog;
dialog.on('show', function () {
console.log('CKEDITOR [dialogdefinition:true] jQuery adapter: schliesse ui-dialog');
$('.ui-dialog-content').dialog('close');
});
dialog.on('hide', function () {
console.log('CKEDITOR [dialogdefinition:false] jQuery adapter: öffne ui-dialog');
$('.ui-dialog-content').dialog('open');
});
});
});
this.editor = this.eq(0).data("ckeditorInstance");
return this
}
});
CKEDITOR.config.jqueryOverrideVal && (a.fn.val = CKEDITOR.tools.override(a.fn.val, function(g) {
return function(d) {
if (arguments.length) {
var m =
this,
k = [],
f = this.each(function() {
var b = a(this),
c = b.data("ckeditorInstance");
if (b.is("textarea") && c) {
var f = new a.Deferred;
c.setData(d, function() {
f.resolve()
});
k.push(f.promise());
return !0
}
return g.call(b, d)
});
if (k.length) {
var b = new a.Deferred;
a.when.apply(this, k).done(function() {
b.resolveWith(m)
});
return b.promise()
}
return f
}
var f = a(this).eq(0),
c = f.data("ckeditorInstance");
return f.is("textarea") && c ? c.getData() : g.call(f)
}
}))
})(window.jQuery);
Also found this solution:
https://forum.jquery.com/topic/can-t-edit-fields-of-ckeditor-in-jquery-ui-modal-dialog

jQuery UI Autocomplete Multiple Values in Textbox

I need a simple autocomplete search functionality but also allowing users to type more than one value. I'm using jQuery UI's autocomplete widget (http://jqueryui.com/autocomplete/) and so far I've set the source to only search for the first letter in the suggestions. What I'd like to add now is the ability for users to search for multiple items from the same textbox. (i.e. after a comma suggestions are shown again)
I have been trying to search on how this could be done. The only thing I've managed to find is an option that could be added multiple: true (http://forum.jquery.com/topic/multiple-values-with-autocomplete). Thing is that it's not even listed in the documentation anymore so I don't know if the option has changed or doesn't exist anymore.
This is my code:
var items = [ 'France', 'Italy', 'Malta', 'England',
'Australia', 'Spain', 'Scotland' ];
$(document).ready(function () {
$('#search').autocomplete({
source: function (req, responseFn) {
var re = $.ui.autocomplete.escapeRegex(req.term);
var matcher = new RegExp('^' + re, 'i');
var a = $.grep(items, function (item, index) {
return matcher.test(item);
});
responseFn(a);
}
});
});
What I tried:
var items = [ 'France', 'Italy', 'Malta', 'England',
'Australia', 'Spain', 'Scotland' ];
$(document).ready(function () {
$('#search').autocomplete({
source: function (req, responseFn) {
var re = $.ui.autocomplete.escapeRegex(req.term);
var matcher = new RegExp('^' + re, 'i');
var a = $.grep(items, function (item, index) {
return matcher.test(item);
});
responseFn(a);
},
multiple: true
});
});
Try this:
function split( val ) {
return val.split( /,\s*/ );
}
function extractLast( term ) {
return split( term ).pop();
}
$( "#search" )
.autocomplete({
minLength: 0,
source: function( request, response ) {
response( $.ui.autocomplete.filter(
items, extractLast( request.term ) ) );
},
focus: function() {
return false;
},
select: function( event, ui ) {
var terms = split( this.value );
terms.pop();
terms.push( ui.item.value );
terms.push( "" );
this.value = terms.join( ", " );
return false;
}
});
SEE DEMO
To solve the issue of multiple strings in the same textbox AND include a regex to only show suggestions matching the start of the string I did the following:
$('#search').autocomplete({
minLength: 1,
source: function (request, response) {
var term = request.term;
// substring of new string (only when a comma is in string)
if (term.indexOf(', ') > 0) {
var index = term.lastIndexOf(', ');
term = term.substring(index + 2);
}
// regex to match string entered with start of suggestion strings
var re = $.ui.autocomplete.escapeRegex(term);
var matcher = new RegExp('^' + re, 'i');
var regex_validated_array = $.grep(items, function (item, index) {
return matcher.test(item);
});
// pass array `regex_validated_array ` to the response and
// `extractLast()` which takes care of the comma separation
response($.ui.autocomplete.filter(regex_validated_array,
extractLast(term)));
},
focus: function () {
return false;
},
select: function (event, ui) {
var terms = split(this.value);
terms.pop();
terms.push(ui.item.value);
terms.push('');
this.value = terms.join(', ');
return false;
}
});
function split(val) {
return val.split(/,\s*/);
}
function extractLast(term) {
return split(term).pop();
}
If you want to implement the focus function instead of returning false, it's:
focus: function (event, ui) {
var terms = split(this.value);
terms.pop();
terms.push(ui.item.value);
this.value = terms.join(', ');
return false;
},
If you do this though, you should probably extract commas from the values.
Also, you can replace lines 7-10 with a call to extractLast. And then you can get rid of your other extractLast because you already called it on term.
With all my changes:
$('#search').autocomplete({
minLength: 1,
source: function (request, response) {
var term = extractLast(request.term),
re = $.ui.autocomplete.escapeRegex(term),
matcher = new RegExp('^' + re, 'i'),
regex_validated_array = $.grep(items, function (item, index) {
return matcher.test(item);
}),
mapped_array = regex_validated_array.map(function (item) {
return value.replace(/,/g, '');
});
response($.ui.autocomplete.filter(mapped_array, term));
},
focus: function () {
var terms = split(this.value);
terms.pop();
terms.push(ui.item.value);
this.value = terms.join(', ');
return false;
},
select: function (event, ui) {
var terms = split(this.value);
terms.pop();
terms.push(ui.item.value);
terms.push('');
this.value = terms.join(', ');
return false;
}
});
function split(val) {
return val.split(/,\s*/);
}
function extractLast(term) {
return split(term).pop();
}

ASP.NET MVC Jquery Ajax post form serialize?

Ajax function
$(function () {
$('form').submit(function () {
if ($(this).valid()) {
$.ajax({
url: this.action,
type: this.method,
data: { model: $(this).serialize(), locations: getCheckedLocation(), reports: getCheckedReports() },
beforeSend: function () {
},
complete: function () {
},
success: function (result) {
$('#user_operations_container').html(result);
setTimeout(function () { LoadAction('#Url.Action("GetAllUsers", "User")') }, 1000);
$("#widgets ul li a").removeClass("link_active");
$("#widgets ul li:first-child a").addClass("link_active");
}
});
}
return false;
});
});
functions that are using in ajax data attribute
function getCheckedLocation() {
var nodes = $('#tt_location').tree('getChecked');
var s = '';
for (var i = 0; i < nodes.length; i++) {
if (s != '') s += ',';
s += nodes[i].text;
}
return s;
}
function getCheckedReports() {
var nodes = $('#tt_reports').tree('getChecked');
var s = '';
for (var i = 0; i < nodes.length; i++) {
if (s != '') s += ',';
s += nodes[i].text;
}
return s;
}
HTML
<div> // there are html helpers for model (dropdownlistfor, textboxfor,...)
</div>
<div> // checkbox tree (#tt_location)
</div>
<div> // checkbox tree (#tt_reports)
</div>
Controller
[HttpPost]
public ActionResult _EditUser(UserViewModel model,string locations,string reports)
{
// model = null
// locations and reports are expected. (not null)
}
Question
Why model is null?
When I use ajax data attribute like this = data: $(this).serialize(), , It works model is not null.
How can I post model, with additional data (locations,reports).
I hope I can explain. Thanks...
Try like this:
data:$('this').serialize() + "&locations=" + getCheckedLocation() "&reports=" + getCheckedReports()
It will work.
Hope it helps

Uploadify - How to capture the newly created ID for scriptdata?

I have solved the problem myself now, below is the solution:
No problem any more. I am only writing this to get my text validated.
<script type="text/javascript">
/***************************************************/
/* THIS VARIABLE IS USED TO TRANSPORT THE NEW ID. */
var assignmentId;
/***************************************************/
$("#btnSave").click
(
function () {
var inputData = $("form").serialize();
var url = $("form").attr("action");
$.post(url, inputData, function (data) {
/********************************************************/
/* NOW UPLOADIFY GETS THE NEW ID!! */
assignmentId = data.AssignmentID;
alert(assignmentId.toString());
$('#fileuploader').uploadifySettings("scriptData", { 'currentValue': assignmentId });
/********************************************************/
$('#fileuploader').uploadifyUpload();
});
}
);
$("#fileuploader").uploadify({
'uploader': '#Url.Content("/Scripts/uploadify/uploadify.swf")',
'cancelImg': '/Scripts/uploadify/cancel.png',
'buttonText': 'Browse For File',
'script': '#Url.Action("Upload")',
'folder': '/uploads',
'scriptData': { 'currentValue': assignmentId },
'onAllComplete': function (event, data) { window.location = "/Assignment/" + assignmentId; },
'onError': function (a, b, c, d) {
},
'onSelectOnce': function (event, data) { noFilesToUpload = false; },
'fileDesc': 'Media Files',
'fileExt': '*.jpg;*.jpeg;',
'sizeLimit': 27000000,
'multi': false,
'auto': false
});
</script>
Thank you!
I have solved the problem myself now, below is the solution:
No problem any more. I am only writing this to get my text validated.
<script type="text/javascript">
/***************************************************/
/* THIS VARIABLE IS USED TO TRANSPORT THE NEW ID. */
var assignmentId;
/***************************************************/
$("#btnSave").click
(
function () {
var inputData = $("form").serialize();
var url = $("form").attr("action");
$.post(url, inputData, function (data) {
/********************************************************/
/* NOW UPLOADIFY GETS THE NEW ID!! */
assignmentId = data.AssignmentID;
alert(assignmentId.toString());
$('#fileuploader').uploadifySettings("scriptData", { 'currentValue': assignmentId });
/********************************************************/
$('#fileuploader').uploadifyUpload();
});
}
);
$("#fileuploader").uploadify({
'uploader': '#Url.Content("/Scripts/uploadify/uploadify.swf")',
'cancelImg': '/Scripts/uploadify/cancel.png',
'buttonText': 'Browse For File',
'script': '#Url.Action("Upload")',
'folder': '/uploads',
'scriptData': { 'currentValue': assignmentId },
'onAllComplete': function (event, data) { window.location = "/Assignment/" + assignmentId; },
'onError': function (a, b, c, d) {
},
'onSelectOnce': function (event, data) { noFilesToUpload = false; },
'fileDesc': 'Media Files',
'fileExt': '*.jpg;*.jpeg;',
'sizeLimit': 27000000,
'multi': false,
'auto': false
});
</script>

Resources