Related
I am creating a pluging based in Jquery and Bootrap (Laste Versions), that is call by this method/code:
$(document).find('.calendar-plug-bs').each(function(index, el) {
//$(this).plgCalendar("destroy"); Testing for destroy if exist...
$(this).plgCalendar();
})
it work with and element like this:
<div class="form-group row">
<div class="calendar-plug-bs"></div>
</div>
and this script/plugin starts as follows ...
(function($) {
$.fn.plgCalendar = function(param) {
return window.plgCalendar(param);
};
}(jQuery));
But the problem is that i need retrive node that call the initial function...
|------|
$(this).plgCalendar();
to add a table inside it ...
function plgCalendar(param = null) {
var r = null;
if (param !== null) {
if (typeof param.func !== 'undefined') {
if (param.func === "destroy") {
} else if (param.func === "getValue") {
}
} else {
console.log('%cMSG: (func) not Set', 'color: #bada55');
}
} else {
/*****WORKING ON THIS***/
var target = $(this);
console.log(target);
if (target.is("div")) {
var id = window.BuildRandID();
var $tableObject = $('<table/>', {
'class': 'bigger',
'id': id
});
$(target).append($tableObject);
return id;
} else {
window.alert("calendar-plug-bs must be a div");
}
/*****WORKING ON THIS***/
}
return r;
}
the fail is that var taget not is a div... and i dont know how to retrive...
resolve by this way:
(function($) {
$.fn.plgCalendar = function(param = null) {
param = window.plgCalendarParam(param);
param['this'] = $(this);
return window.plgCalendar(param);
};
}(jQuery));
function plgCalendarParam(param) {
if (param == null) {
param = [];
}
return param;
}
function plgCalendar(param) {
var r = null;
if (typeof param.func !== 'undefined') {
if (param.func === "destroy") {
} else if (param.func === "getValue") {
}
} else {
/*****WORKING ON THIS***/
var target = param['this'];
if (target.is("div")) {
var id = 'plgCalendar_' + window.BuildRandID();
var $tableObject = $('<table/>', {
'class': 'bigger',
'id': id
});
$(target).append($tableObject);
r = { 'id': id, 'init': true };
} else {
window.alert("calendar-plug-bs must be a div");
}
/*****WORKING ON THIS***/
}
return r;
}
I have created a JavaScript plugin, I'd like to have the potential to use this multiple times, however, having it called one the page twice like follows doesn't seem to make a new instance:
var lightbox = new MarvLightbox({
imagesContainer: 'detail-hdr__detail-images',
limit: 11
});
var lightbox2 = new MarvLightbox({
imagesContainer: 'image-grid-2',
galleryFolder: 2,
mobileFolder: 0
});
The following code seems to be returning the same values, so for example, if I click an image to set the c value within the state object then it's changed for instance lightbox2 AND lightbox.
MarvLightbox.prototype.current = function() {
console.log(state);
};
I have tried to remove any none required code from my plugin. But what I'm basically doing is:
1. Compile a list of the images within a container.
2. Generate HTML from a JSON string.
3. Assigning click events to the images, and then when clicked they open the lightbox and change the image etc.
(function() {
var instance = null,
container;
// Constructor
this.MarvLightbox = function() {
instance = this;
// Create global variables
this.images_count = -1;
this.active = false;
this.error = false;
this.debug = false;
// Define option defaults
var defaults = {
activeClass: 'marvLightbox',
appendTo: '#wrapper',
imagesContainer: null,
thumbClass: null,
lightboxId: 'marvLightbox',
galleryFolder: null,
mobileFolder: null,
showAlt: true,
showMax: true,
limit: null,
html: '{ "div": { "id": "{lightboxId}", "0": { "div": { "class": "{lightboxId}__container", "data-click": "EventClose", "0": { "div": { "class": "{lightboxId}__controls {lightboxId}__controls--top", "0": { "div": { "class": "{lightboxId}__eschint", "content": "Press <span>ESC</span> to close" } }, "1": { "div": { "class": "{lightboxId}__close", "data-click": "EventClose" } } } }, "1": { "div": { "class": "{lightboxId}__image", "0": { "img": { "src": "", "class": "responsive-img image", "data-click": "EventRight" } } } }, "2": { "div": { "class": "{lightboxId}__controls {lightboxId}__controls--bottom", "3": { "div": { "class": "{lightboxId}__left", "data-click": "EventLeft", "data-hover": "EventClass(#{lightboxId}, toggle: left)" } }, "4": { "div": { "class": "{lightboxId}__right", "data-click": "EventRight", "data-hover": "EventClass(#{lightboxId}, toggle: right)" } }, "5": { "div": { "class": "{lightboxId}__alt" } }, "6": { "div": { "class": "{lightboxId}__num" } } } } } } } }'
};
// Create options by extending defaults with the passed in arugments
if (arguments[0] && typeof arguments[0] === "object") {
this.options = extendDefaults(defaults, arguments[0]);
}
this.options.html = this.options.html.replace(/\{(lightboxId)}/g, this.options.lightboxId);
// this.options.limit = this.options.limit + 1;
// Check if debugging is enabled
(function() {
var args = document.querySelectorAll('[data-external-arg]');
if(args.length > 0 && args[0].src.indexOf('marv.lightbox') !== -1) {
if (args[0].dataset.externalArg === 'debug') instance.debug = true;
}
}());
// Initialise plugin
this.init();
};
// Debugging messages
var debug = function(code, arg) {
var args = function(n) {
if (arg === undefined) {
return '[arg undefined]';
}
if (arg[n] === undefined) {
return '[arg undefined]';
} else {
return arg[n];
}
};
var messages = function(code, argument) {
return [
'marv.lightbox(debug): Debugging mode is on, make sure you turn this off before you launch',
'marv.lightbox(debug): HTMLElement(' + args(0) + ') with the name of ' + args(1) + ' has been detected',
'marv.lightbox(debug): Found '+ arg + ' image/s within your Lightbox container ',
'marv.lightbox(debug): ' + args(0) + ' key pressed, changing current (' + args(1) + '), number of images (' + args(2) + ')',
'marv.lightbox(debug): Current is set to null, closing lightbox',
'marv.lightbox(debug): Inserting Lightbox within HTMLElement(' + args(1) + '), using ' + args(0),
'marv.lightbox(debug): 1 image found, don\'t add previous/next arrows, don\'t show numbers either',
'marv.lightbox(debug): showAlt set to false, don\'t display alt text',
'marv.lightbox(debug): showMax set to false, don\'t display numbers below alt text',
'marv.lightbox(debug): Reverting to mobile version (' + instance.options.mobileFolder + ') of images',
'marv.lightbox(debug): Over-riding to ' + instance.options.galleryFolder + ' version of images'
][code];
};
if (instance.debug === true)
console.log(messages(code, arg));
};
// Error messages
var error = function(code, arg) {
var args = function(n) {
if (arg === undefined) {
return '[arg undefined]';
}
if (arg[n] === undefined) {
return '[arg undefined]';
} else {
return arg[n];
}
};
var messages = function(code, argument) {
return [
'marv.lightbox(error): I need to know which images to use... add { imagesContainer: "id/class" } to the plugin initialization',
'marv.lightbox(error): The HTML structure provided appears to have an error: ' + arg,
'marv.lightbox(error): Issue compiling list of images, speak to Dev, error: ' + arg,
'marv.lightbox(error): Your going to need some images for this to work... make sure they have the class: ' + instance.options.thumbClass,
'marv.lightbox(error): I was unable to find an element which matches ' + instance.options.imagesContainer + ', please double check this',
'marv.lightbox(error): I was unable to find a container with the name of ' + args[0],
'marv.lightbox(error): EventListener with arguments passed, had an issue seperating arguments, check formatting',
'marv.lightbox(error): Unable to apply class event to element, please check your attribute',
'marv.lightbox(error): You have attempted to over-ride the images folder with a size that doesn\'t exist, please choose a size between 0 and ' + arg
][code];
};
console.log(messages(code, arg));
};
var imageSizes = function(e) {
var sizes = [ '344x258', 'full', 'large1' ];
if (sizes[e] !== undefined) {
return sizes[e];
}
error(8, sizes.length);
};
// Initilise the plugin
MarvLightbox.prototype.init = function() {
if (this.options.imagesContainer === null) {
error(0);
return;
}
container = (instance.options.imagesContainer).objectType();
if (container === null || container === undefined) {
error(4);
return;
}
debug(0);
setupLightbox();
};
// Generate HTML from JSON
function buildHTML(json) {
"use strict";
var handleAttribute = function(element, attribute, value) {
if (value instanceof HTMLElement) {
return element.appendChild(value);
}
switch (attribute) {
case 'class':
case 'src':
case 'id':
case 'data-click':
case 'data-hover':
return element.setAttribute(attribute, value);
case 'content':
element.innerHTML = value;
return;
// other keys...
default:
console.log(element.tagName, attribute, value);
}
};
var htmlReviver = function(key, value) {
// parse as element
if (isNaN(key) && typeof value === 'object') {
var element = document.createElement(key);
var subValue;
for (var attribute in value) {
handleAttribute(element, attribute, value[attribute]);
}
return element;
// move element from { index: { tagName: Element } } to { index: Element }
} else if (!isNaN(key)) {
return value[Object.keys(value)[0]];
// leave property alone
} else {
return value;
}
};
try {
var htmlObject = JSON.parse(json, htmlReviver);
return htmlObject;
} catch (e) {
error(1, e);
}
}
// Manage item change
var images_compiled;
var state = {
c: null,
altValue: null,
maxValue: null,
get current() { return this.c; },
get max() { return this.maxValue; },
get alt() { return this.altValue; },
set max(e) { this.maxValue = e; },
set alt(e) { this.altValue = e; },
set current(e) {
if (this.c !== null) {
// Remove class from current
(images_compiled[this.c].target).classList.remove('expand');
}
if (e === null) {
debug(4);
// Collapse Lightbox
if (document.getElementById(instance.options.lightboxId)) {
(images_compiled[this.c].target).classList.remove('expand');
document.getElementsByTagName('body')[0].classList.remove(instance.options.activeClass);
(document.getElementById(instance.options.lightboxId).parentNode).removeChild(document.getElementById(instance.options.lightboxId));
}
this.c = e;
return;
}
// Change current element, update lightbox
this.c = e;
var lightbox = document.getElementById(instance.options.lightboxId),
res;
// Check lightbox exists, if so change the image src
if (lightbox) {
var image = images_compiled[e].image.src;
if (instance.options.galleryFolder !== null) {
var filter = image.match(/([^\/]*)/g).filter(Boolean);
image = image.replace(filter[filter.length - 2], imageSizes(instance.options.galleryFolder));
}
lightbox.getElementsByTagName('img')[0].src = image;
if (instance.options.showAlt) {
debug(7);
lightbox.getElementsByClassName(instance.options.lightboxId + '__alt')[0].innerHTML = images_compiled[e].alt;
}
if (instance.options.showMax && this.max > 1) {
debug(8);
lightbox.getElementsByClassName(instance.options.lightboxId + '__num')[0].innerHTML = (images_compiled[e].index + 1) + '/' + this.max;
}
} else {
res = generateExpand(images_compiled[e]);
}
// Add active class
if (res) {
(images_compiled[e].target).classList.add('expand');
document.getElementsByTagName('body')[0].classList.add(instance.options.lightboxId);
}
}
};
// Setup light box
function setupLightbox() {
var images;
images = container.getElementsByTagName('img');
if (instance.options.limit !== null) {
var tmp = [];
for (var i = 0, length = images.length; i < length; i++) {
if (i < instance.options.limit) {
tmp.push(images[i]);
}
}
images = tmp;
}
if (images.length < 1 || images === undefined) {
error(3);
return;
}
try {
images_compiled = Array.from(images, function(el) {
// Generate array of objects containing image information
instance.images_count++;
return {
target: function() {
if (el.parentElement.nodeName === 'A') {
return el.parentElement;
}
return el;
}(),
index: instance.images_count,
alt: ((el.alt) ? el.alt : ''),
image: function() {
// If class put on an A link then find the image
if (el.tagName === 'A') {
return el.getElementsByTagName('img')[0];
} else {
return el;
}
}()
};
});
} catch(e) {
// Issue with generating array
error(2, e);
}
debug(2, images_compiled.length);
// Add image click event
images_compiled.forEach(function(el) {
if (el !== null) {
var elm = el.target;
elm.addEventListener('click', function(e) {
if (elm.nodeName === 'A') {
e.preventDefault();
}
instance.active = true;
if (state.current === el.index) {
state.current = null;
return;
}
state.current = el.index;
state.alt = el.alt;
});
}
});
state.max = images_compiled.length;
}
function generateExpand(img) {
// Generate lightbox HTML and append
var html = buildHTML(instance.options.html);
instance.events = {
EventClose: function(evt) {
if (evt !== undefined) {
evt.stopPropagation();
}
instance.active = false;
state.current = null;
},
EventLeft: function(evt) {
if (evt !== undefined) {
evt.stopPropagation();
}
if (state.current !== 0 && state.max > 1) {
state.current = state.current - 1;
} else {
state.current = instance.images_count;
}
},
EventRight: function(evt) {
if (evt !== undefined) {
evt.stopPropagation();
}
if (state.current !== instance.images_count && state.max > 1) {
state.current = state.current + 1;
} else {
state.current = 0;
}
},
EventClass: function(evt) {
var arg = (evt.dataset.hover).replace(/ /g,''),
args = (arg.match(/[^(]*/g).filter(Boolean))[1].match(/(?:([^,()]+)?)+/g).filter(Boolean),
target = args[0].objectType(),
action = args[1].match(/^(.*):(.*)/).filter(Boolean);
switch(action[1]) {
case 'add':
// Add class
target.classList.add(action[2]);
break;
case 'remove':
// Remove class
target.classList.remove(action[2]);
break;
case 'toggle':
target.classList.add(action[2]);
evt.addEventListener('mouseout', function() {
target.classList.remove(action[2]);
});
break;
default:
// Error
error(7);
break;
}
}
};
// Lightbox is active
instance.active = true;
// Assign event listeners
Array.prototype.forEach.call(html.querySelectorAll('[data-click]'), function (e) {
e.addEventListener('click', instance.events[eventName(e.dataset.click)]);
});
Array.prototype.forEach.call(html.querySelectorAll('[data-hover]'), function (e) {
e.addEventListener('mouseover', function() { instance.events[eventName(e.dataset.hover)](e); });
});
// Insert lightbox into website
var appendTo = (instance.options.appendTo).objectType();
if (appendTo === null || (instance.options.appendTo).objectType() === undefined) {
error(5, [instance.options.appendTo]);
return false;
}
debug(5, ['id', instance.options.imagesContainer]);
appendTo.insertBefore(html, appendTo.firstChild);
return true;
}
MarvLightbox.prototype.current = function() {
console.log(state);
};
}());
As I said above though the state object appears to be shared between both instances, it should be unique.
The problem lies at instance i think:
var instance = null;
MarvLightbox = function() {
instance = this;
So whenever a new Lightbox is created, instance points to it. This also applies to asynchronous callback functions which will all point to the last instead of the current instance. You may scope instance locally:
var instance=this;
Same applies to state:
MarvLightbox.prototype.current = function() {
console.log(this.state); //make it an objects property, not global
};
I'm working on my first Chrome extension to help me on my job.
Well, I have a HTML file as the extension pop-up and a .JS file to do all the magic. When I run the HTML in the browser, it works fine (it has to autocomplete the keywords are being typed) but when I run it as a Chrome extension it does not work at all.
Any idea?
JSON file
{
"name": "Autocompleter",
"version": "0",
"description": "It completes!",
"manifest_version": 2,
"browser_action": {
"name": "project with jquery",
"icons": ["icon.png"],
"default_icon": "icon.png",
"default_popup": "home.html"
},
"content_scripts": [ {
"js": [ "awesomplete.js" ],
"matches": [ "http://*/*", "https://*/*"]
}]
}
HTML
<!doctype html>
<html lang="en">
<head>
<script src="awesomplete.js"></script>
<link rel="stylesheet" href="awesomplete.css" />
</head>
<body>
<section id="multiple-values">
<input data-list="Brazil, Argentina, Uruguai, Paraguai, Nova Zelândia, Canadá" data-multiple data-minchars="1" /></label>
<pre class="language-javascript"><code><script>new Awesomplete('input[data-multiple]', {
filter: function(text, input) {
return Awesomplete.FILTER_CONTAINS(text, input.match(/[^,]*$/)[0]);
},
replace: function(text) {
var before = this.input.value.match(/^.+,\s*|/)[0];
this.input.value = before + text + ", ";
}
});</script></code></pre>
</section>
</body>
</html>
.JS file
(function () {
var _ = function (input, o) {
var me = this;
// Setup
this.isOpened = false;
this.input = $(input);
this.input.setAttribute("autocomplete", "off");
this.input.setAttribute("aria-autocomplete", "list");
o = o || {};
configure(this, {
minChars: 2,
maxItems: 10,
autoFirst: false,
data: _.DATA,
filter: _.FILTER_CONTAINS,
sort: _.SORT_BYLENGTH,
item: _.ITEM,
replace: _.REPLACE
}, o);
this.index = -1;
// Create necessary elements
this.container = $.create("div", {
className: "awesomplete",
around: input
});
this.ul = $.create("ul", {
hidden: "hidden",
inside: this.container
});
this.status = $.create("span", {
className: "visually-hidden",
role: "status",
"aria-live": "assertive",
"aria-relevant": "additions",
inside: this.container
});
// Bind events
$.bind(this.input, {
"input": this.evaluate.bind(this),
"blur": this.close.bind(this, { reason: "blur" }),
"keydown": function(evt) {
var c = evt.keyCode;
// If the dropdown `ul` is in view, then act on keydown for the following keys:
// Enter / Esc / Up / Down
if(me.opened) {
if (c === 13 && me.selected) { // Enter
evt.preventDefault();
me.select();
}
else if (c === 27) { // Esc
me.close({ reason: "esc" });
}
else if (c === 38 || c === 40) { // Down/Up arrow
evt.preventDefault();
me[c === 38? "previous" : "next"]();
}
}
}
});
$.bind(this.input.form, {"submit": this.close.bind(this, { reason: "submit" })});
$.bind(this.ul, {"mousedown": function(evt) {
var li = evt.target;
if (li !== this) {
while (li && !/li/i.test(li.nodeName)) {
li = li.parentNode;
}
if (li && evt.button === 0) { // Only select on left click
evt.preventDefault();
me.select(li, evt.target);
}
}
}});
if (this.input.hasAttribute("list")) {
this.list = "#" + this.input.getAttribute("list");
this.input.removeAttribute("list");
}
else {
this.list = this.input.getAttribute("data-list") || o.list || [];
}
_.all.push(this);
};
_.prototype = {
set list(list) {
if (Array.isArray(list)) {
this._list = list;
}
else if (typeof list === "string" && list.indexOf(",") > -1) {
this._list = list.split(/\s*,\s*/);
}
else { // Element or CSS selector
list = $(list);
if (list && list.children) {
var items = [];
slice.apply(list.children).forEach(function (el) {
if (!el.disabled) {
var text = el.textContent.trim();
var value = el.value || text;
var label = el.label || text;
if (value !== "") {
items.push({ label: label, value: value });
}
}
});
this._list = items;
}
}
if (document.activeElement === this.input) {
this.evaluate();
}
},
get selected() {
return this.index > -1;
},
get opened() {
return this.isOpened;
},
close: function (o) {
if (!this.opened) {
return;
}
this.ul.setAttribute("hidden", "");
this.isOpened = false;
this.index = -1;
$.fire(this.input, "awesomplete-close", o || {});
},
open: function () {
this.ul.removeAttribute("hidden");
this.isOpened = true;
if (this.autoFirst && this.index === -1) {
this.goto(0);
}
$.fire(this.input, "awesomplete-open");
},
next: function () {
var count = this.ul.children.length;
this.goto(this.index < count - 1 ? this.index + 1 : (count ? 0 : -1) );
},
previous: function () {
var count = this.ul.children.length;
var pos = this.index - 1;
this.goto(this.selected && pos !== -1 ? pos : count - 1);
},
// Should not be used, highlights specific item without any checks!
goto: function (i) {
var lis = this.ul.children;
if (this.selected) {
lis[this.index].setAttribute("aria-selected", "false");
}
this.index = i;
if (i > -1 && lis.length > 0) {
lis[i].setAttribute("aria-selected", "true");
this.status.textContent = lis[i].textContent;
$.fire(this.input, "awesomplete-highlight", {
text: this.suggestions[this.index]
});
}
},
select: function (selected, origin) {
if (selected) {
this.index = $.siblingIndex(selected);
} else {
selected = this.ul.children[this.index];
}
if (selected) {
var suggestion = this.suggestions[this.index];
var allowed = $.fire(this.input, "awesomplete-select", {
text: suggestion,
origin: origin || selected
});
if (allowed) {
this.replace(suggestion);
this.close({ reason: "select" });
$.fire(this.input, "awesomplete-selectcomplete", {
text: suggestion
});
}
}
},
evaluate: function() {
var me = this;
var value = this.input.value;
if (value.length >= this.minChars && this._list.length > 0) {
this.index = -1;
// Populate list with options that match
this.ul.innerHTML = "";
this.suggestions = this._list
.map(function(item) {
return new Suggestion(me.data(item, value));
})
.filter(function(item) {
return me.filter(item, value);
})
.sort(this.sort)
.slice(0, this.maxItems);
this.suggestions.forEach(function(text) {
me.ul.appendChild(me.item(text, value));
});
if (this.ul.children.length === 0) {
this.close({ reason: "nomatches" });
} else {
this.open();
}
}
else {
this.close({ reason: "nomatches" });
}
}
};
// Static methods/properties
_.all = [];
_.FILTER_CONTAINS = function (text, input) {
return RegExp($.regExpEscape(input.trim()), "i").test(text);
};
_.FILTER_STARTSWITH = function (text, input) {
return RegExp("^" + $.regExpEscape(input.trim()), "i").test(text);
};
_.SORT_BYLENGTH = function (a, b) {
if (a.length !== b.length) {
return a.length - b.length;
}
return a < b? -1 : 1;
};
_.ITEM = function (text, input) {
var html = input === '' ? text : text.replace(RegExp($.regExpEscape(input.trim()), "gi"), "<mark>$&</mark>");
return $.create("li", {
innerHTML: html,
"aria-selected": "false"
});
};
_.REPLACE = function (text) {
this.input.value = text.value;
};
_.DATA = function (item/*, input*/) { return item; };
// Private functions
function Suggestion(data) {
var o = Array.isArray(data)
? { label: data[0], value: data[1] }
: typeof data === "object" && "label" in data && "value" in data ? data : { label: data, value: data };
this.label = o.label || o.value;
this.value = o.value;
}
Object.defineProperty(Suggestion.prototype = Object.create(String.prototype), "length", {
get: function() { return this.label.length; }
});
Suggestion.prototype.toString = Suggestion.prototype.valueOf = function () {
return "" + this.label;
};
function configure(instance, properties, o) {
for (var i in properties) {
var initial = properties[i],
attrValue = instance.input.getAttribute("data-" + i.toLowerCase());
if (typeof initial === "number") {
instance[i] = parseInt(attrValue);
}
else if (initial === false) { // Boolean options must be false by default anyway
instance[i] = attrValue !== null;
}
else if (initial instanceof Function) {
instance[i] = null;
}
else {
instance[i] = attrValue;
}
if (!instance[i] && instance[i] !== 0) {
instance[i] = (i in o)? o[i] : initial;
}
}
}
// Helpers
var slice = Array.prototype.slice;
function $(expr, con) {
return typeof expr === "string"? (con || document).querySelector(expr) : expr || null;
}
function $$(expr, con) {
return slice.call((con || document).querySelectorAll(expr));
}
$.create = function(tag, o) {
var element = document.createElement(tag);
for (var i in o) {
var val = o[i];
if (i === "inside") {
$(val).appendChild(element);
}
else if (i === "around") {
var ref = $(val);
ref.parentNode.insertBefore(element, ref);
element.appendChild(ref);
}
else if (i in element) {
element[i] = val;
}
else {
element.setAttribute(i, val);
}
}
return element;
};
$.bind = function(element, o) {
if (element) {
for (var event in o) {
var callback = o[event];
event.split(/\s+/).forEach(function (event) {
element.addEventListener(event, callback);
});
}
}
};
$.fire = function(target, type, properties) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent(type, true, true );
for (var j in properties) {
evt[j] = properties[j];
}
return target.dispatchEvent(evt);
};
$.regExpEscape = function (s) {
return s.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
};
$.siblingIndex = function (el) {
/* eslint-disable no-cond-assign */
for (var i = 0; el = el.previousElementSibling; i++);
return i;
};
// Initialization
function init() {
$$("input.awesomplete").forEach(function (input) {
new _(input);
});
}
// Are we in a browser? Check for Document constructor
if (typeof Document !== "undefined") {
// DOM already loaded?
if (document.readyState !== "loading") {
init();
}
else {
// Wait for it
document.addEventListener("DOMContentLoaded", init);
}
}
_.$ = $;
_.$$ = $$;
// Make sure to export Awesomplete on self when in a browser
if (typeof self !== "undefined") {
self.Awesomplete = _;
}
// Expose Awesomplete as a CJS module
if (typeof module === "object" && module.exports) {
module.exports = _;
}
return _;
}());
Prints:
Working
Not working (as a Chrome Extension)
I am working on JQuery mechanism that is building tree, it has to be as fast as possible. Volume of data is quite large so master record column is used to be able to 'grab' all relevant nodes in one select from webSQL db.
Whole mechanism but one part is done, when assembling tree it must check that there is no infinite recursion being created. What mechanism does at the moment if Record A is Master and Parent of record B, and Record B is Master and Parent of record A then structure like A.Children[0] = B and B.Children[0] = A is being built. It all would work fine, but it has do be knockout.js bound and displayed as expandable list to users, which results in overflow when trying to display the tree.
Requirement is to detect such loops and do not create tree relationships.
Mechanism that would check if item is already in the tree I came up is:
function InTree(master, item) {
return $.inArray(item, $.map(master, function recurs(n) {
return ($.isArray(n) ? $.map(n, recurs) : n);
})) != -1;
}
if(!InTree(tree, record))
{
//attach
} else {
// get next record
}
Is there anything faster than InTree() function that would get me if item is in the tree?
Whole tree building algorithm is below (not that I think it is relevant but rather to avoid the comments 'show the code')
$(document).on('OnPreQuery', onTheMove.PageDataRoles, function (e, options) {
var isChildAttachmentQueued = true;
var knockoutContextName = options.knockoutContextName;
if (TreeEnabled(knockoutContextName)) {
var isModelReadyToAttachChildren = function () {
var isReady = false;
if (PageObj[knockoutContextName] != undefined) {
isReady = (PageObj[knockoutContextName]().length > 0) && isChildAttachmentQueued;
}
return isReady;
};
var businessComponent = eval(knockoutContextName);
var treeSettings = businessComponent.Tree;
treeSettings.knockoutContextName = knockoutContextName;
$(businessComponent).on('OnPreUIUpdate', function (e, options) {
if (isModelReadyToAttachChildren()) {
getChildrenForMasterRecordList({
parentTable: businessComponent.primaryTableName,
knockoutContextName: treeSettings.knockoutContextName,
parentIdColumn: treeSettings.ParentIdColumn,
masterIdColumn: treeSettings.MasterIdColumn
});
isChildAttachmentQueued = false;
}
});
}
});
function TreeEnabled(knockoutContextName) {
var isTreeEnabled = false;
try {
eval(knockoutContextName);
} catch (e) {
return isTreeEnabled;
}
var treeSettings = eval(knockoutContextName).Tree;
if (treeSettings && treeSettings.IncludeChildren) {
isTreeEnabled = true;
}
return isTreeEnabled;
}
function ComposeRecordsToTreeStructure(results, tableArray, columnArray, options) {
if (results.rows.length > 0) {
if (options.parentLayerIdList == undefined) {
options.parentLayerIdList = options.masterIdList;
}
if (options.orphans == undefined) {
options.orphans = [];
}
var knockoutContextName = options.knockoutContextName;
var childRecordIdArray = [];
if (options.runningOnOrphans) {
if (options.orphans.length > 0) {
for (var j = 0; j < options.orphans.length; j++) {
var rowRecord = options.orphans[j];
var rowRecordParentId = rowRecord[options.parentIdColumn];
var result = EstablishParentChildConnectionOnAlreadyProcessedNodes(rowRecord, rowRecordParentId, options.parentLayerIdList, knockoutContextName, childRecordIdArray, options);
if (result.hasEstablishedConnection) {
childRecordIdArray = result.childRecordIdArray;
}
}
options.orphans = $.grep(options.orphans, function (item) {
return $.inArray(item['Id'], childRecordIdArray) == -1;
});
}
} else {
for (var i = 0; i < results.rows.length; i++) {
var rowRecord = results.rows.item(i);
var rowRecordParentId = rowRecord[options.parentIdColumn];
if (rowRecord[options.parentIdColumn] == '' || rowRecord[options.masterIdColumn] == '' || rowRecord[options.masterIdColumn] == rowRecord['Id']) {
rowRecord.isInvalid = true;
} else if ($.inArray(rowRecord['Id'], options.masterIdList) != -1) {
masterRecordClone = $.grep(PageObj[knockoutContextName](), function (item) { return item.Fields.Id() == rowRecord['Id'] })[0];
if (masterRecordClone != undefined && masterRecordClone.Children) {
rowRecord.Children = masterRecordClone.Children;
}
}
if (rowRecord.isInvalid == true) {
if (rowRecord[options.masterIdColumn] != rowRecord['Id']) {
var result = EstablishParentChildConnection(rowRecord, rowRecord[options.masterIdColumn], options.parentLayerIdList, knockoutContextName, childRecordIdArray, options);
if (result.hasEstablishedConnection) {
childRecordIdArray = result.childRecordIdArray;
EstablishParentChildConnectionOnAlreadyProcessedNodes(rowRecord, rowRecordParentId, options.parentLayerIdList, knockoutContextName, childRecordIdArray, options);
}
}
} else {
var result = EstablishParentChildConnectionOnAlreadyProcessedNodes(rowRecord, rowRecordParentId, options.parentLayerIdList, knockoutContextName, childRecordIdArray, options);
if (result.hasEstablishedConnection) {
childRecordIdArray = result.childRecordIdArray;
} else {
var recordObject = AddIsExpandedProperty(rowRecord);
options.orphans.push(recordObject);
options.runningOnOrphans = true;
}
}
}
}
if (options.orphans.length > 0 && childRecordIdArray.length > 0) {
options.parentLayerIdList = childRecordIdArray;
ComposeRecordsToTreeStructure(results, tableArray, columnArray, options);
}
}
onTheMove.seleniumHelper.markPageAsLoaded();
}
function EstablishParentChildConnectionOnAlreadyProcessedNodes(rowRecord, rowRecordParentId, parentLayerIdList, knockoutContextName, childRecordIdArray, options) {
var result = EstablishParentChildConnection(rowRecord, rowRecordParentId, parentLayerIdList, knockoutContextName, childRecordIdArray);
if (result.hasEstablishedConnection) {
childRecordIdArray = result.childRecordIdArray;
} else {
var result = EstablishParentChildConnection(rowRecord, rowRecordParentId, childRecordIdArray, knockoutContextName, childRecordIdArray);
if (result.hasEstablishedConnection) {
childRecordIdArray = result.childRecordIdArray;
} else {
var matchingOrphans = $.grep(options.orphans, function (item) {
return item['Id'] == rowRecordParentId;
});
if (matchingOrphans.length > 0) {
AttachPassedChildRecord(rowRecord, matchingOrphans);
var result = {
hasEstablishedConnection: true
};
}
}
}
return {
childRecordIdArray: childRecordIdArray,
hasEstablishedConnection: result.hasEstablishedConnection
};
}
function EstablishParentChildConnection(rowRecord, rowRecordParentId, parentLayerIdList, knockoutContextName, childRecordIdArray) {
var hasEstablishedConnection = false;
var parentPosition = $.inArray(rowRecordParentId, parentLayerIdList);
if (parentPosition != -1) {
AttachChildRecordsToParents(rowRecord, parentLayerIdList[parentPosition], knockoutContextName);
childRecordIdArray = AddChildRecordsToNextParentList(rowRecord, childRecordIdArray);
childRecordIdArray.push(rowRecord['Id']);
hasEstablishedConnection = true;
}
return {
childRecordIdArray: childRecordIdArray,
hasEstablishedConnection: hasEstablishedConnection
};
}
function AddChildRecordsToNextParentList(childRecord, childRecordIdArray) {
if (childRecord.Children != undefined) {
for (var i = 0; i < childRecord.Children.length; i++) {
childRecordIdArray.push(childRecord.Children[i]['Id']);
if (childRecord.Children[i].Children != undefined) {
AddChildRecordsToNextParentList(childRecord.Children[i], childRecordIdArray);
}
}
}
return childRecordIdArray;
}
function RowsToListDataStructure(results) {
var array = [];
for (var i = 0; i < results.rows.length; i++) {
array.push(results.rows.item(i));
}
return array;
}
function AttachChildRecordsToParents(recordRow, id, knockoutContextName) {
var childTreeOptions = {
id: id,
knockoutContextName: knockoutContextName,
results: []
};
findObjectsInChildTreeById(childTreeOptions);
if (childTreeOptions.results.length > 0) {
AttachPassedChildRecord(recordRow, childTreeOptions.results);
}
}
function AttachPassedChildRecord(recordObject, pageObjParentResults) {
for (var i = 0; i < pageObjParentResults.length; i++) {
if (pageObjParentResults[i].Children == undefined) {
pageObjParentResults[i].Children = [];
}
if ($.grep(pageObjParentResults[i].Children, function (children) {
return children['Id'] == recordObject['Id'];
}).length == 0) {
recordObject = AddIsExpandedProperty(recordObject);
pageObjParentResults[i].Children.push(recordObject);
}
}
}
function AddIsExpandedProperty(recordObject) {
recordObject.IsExpanded = ko.observable(false);
return recordObject;
}
function findObjectsInChildTreeById(options) {
if (options.item == undefined) {
if (typeof PageObj[options.knockoutContextName] != 'undefined') {
for (var item in PageObj[options.knockoutContextName]()) {
findObjectsInChildTreeById({
item: PageObj[options.knockoutContextName]()[item],
id: options.id,
results: options.results
});
}
}
} else {
if (typeof options.item.Fields != 'undefined') {
if (options.item.Fields['Id']() == options.id)
options.results.push(options.item);
} else {
if (options.item['Id'] == options.id)
options.results.push(options.item);
}
if (options.item.Children != undefined) {
for (var item in options.item.Children) {
findObjectsInChildTreeById({
item: options.item.Children[item],
id: options.id,
results: options.results
});
}
}
}
}
function getChildrenForMasterRecordList(options) {
var parentTable = options.parentTable,
masterIdColumn = options.masterIdColumn,
parentIdColumn = options.parentIdColumn,
knockoutContextName = options.knockoutContextName,
masterIds = getParentIdsAndMastersOfParentsFromPageObj(knockoutContextName, masterIdColumn);
for (var item in PageObj[options.knockoutContextName]()) {
AddIsExpandedProperty(PageObj[knockoutContextName]()[item]);
}
var dbManager = new OnTheMoveDatabaseManager();
dbManager.queryDatabase({
statement: {
Tables: [{
Alias: parentTable,
JoinSpec: null,
JoinType: "",
Name: parentTable
}, {
Alias: "Record",
JoinSpec: "Record.Id = " + parentTable + ".Id",
JoinType: "INNER",
Name: "Record"
}],
WhereClause: parentTable + "." + masterIdColumn + " IN ('" + masterIds.join("','") + "') AND Record.RecordType ='" + parentTable + "'",
SelectFields: [{
IsAggregate: false,
Name: "*"
}],
DisablePaging: true,
OrderClause: "Record.Id"
},
knockoutContextName: knockoutContextName,
isObservable: false,
masterIdColumn: masterIdColumn,
masterIdList: masterIds,
parentIdColumn: parentIdColumn,
parentTable: options.parentTable,
success: function (results, tableArray, columnArray, options) {
ComposeRecordsToTreeStructure(results, tableArray, columnArray, options);
}
});
}
function getParentIdsAndMastersOfParentsFromPageObj(knockoutContextName, masterColumnName) {
var list = [];
if (typeof PageObj[knockoutContextName] != 'undefined') {
for (var item in PageObj[knockoutContextName]()) {
if ($.inArray(PageObj[knockoutContextName]()[item].Fields['Id'](), list) == -1) {
list.push(PageObj[knockoutContextName]()[item].Fields['Id']());
}
if (PageObj[knockoutContextName]()[item].Fields[masterColumnName]() != '' && $.inArray(PageObj[knockoutContextName]()[item].Fields[masterColumnName](), list) == -1) {
list.push(PageObj[knockoutContextName]()[item].Fields[masterColumnName]());
}
}
}
return list
}
function InTree(master, item) {
return $.inArray(item, $.map(master, function recurs(n) {
return ($.isArray(n) ? $.map(n, recurs) : n);
})) != -1;
}
it depends on your circumstances. if you're able to run code on add/creation of the tree you may simply create a node id array and do a check like
if(allNodes[searchKey])
//etc
This is a very specific solution of course but technically it'd be as fast as it could possibly be.
This is my first post on StackOverflow and might I say, what a great and helpful resource this is. I have been able to find many answers to my questions and hope to do the same with this one. On to the issue at hand... I am currently using the instafeed.js (http://instafeedjs.com/) script to pull in images from instagram and display them on my site.
What I'm trying to accomplish is to have 9 items display, then if I hit the "next" button, it would replace the current 9 images and load the next 9 images and, if the "previous" button is clicked it would go back and show the previous 9 images.
Currently it only renders one image thumb that scrolls through 9 images then stops. Swapping only the one image at a time. A sample of the current working code with only 1 image displaying can be found here - http://codepen.io/stevenschobert/pen/iHxfw
Here is my JavaScript for the instafeed call:
var count = 1;
var feed;
feed = new Instafeed({
clientId: '68be8b63013048ff81bb4ac8b02b606e',
limit: 9,
resolution: 'standard_resolution',
template: '<img src="{{image}}" /><div class="likes">♥ {{likes}}</div>',
mock: true,
after: function () {
var images = $("#instafeed").find('a');
$.each(images, function(index, image) {
var delay = (index * 75) + 'ms';
$(image).css('-webkit-animation-delay', delay);
$(image).css('-moz-animation-delay', delay);
$(image).css('-ms-animation-delay', delay);
$(image).css('-o-animation-delay', delay);
$(image).css('animation-delay', delay);
$(image).addClass('animated fadeInUp pic-'+count++);
});
},
custom: {
images: [],
currentImage: 0,
showImage: function () {
var result, image;
image = this.options.custom.images[this.options.custom.currentImage];
result = this._makeTemplate(this.options.template, {
model: image,
id: image.id,
link: image.link,
image: image.images[this.options.resolution].url,
caption: this._getObjectProperty(image, 'caption.text'),
likes: image.likes.count,
comments: image.comments.count,
location: this._getObjectProperty(image, 'location.name')
});
$("#instafeed").html(result);
}
},
success: function (data) {
this.options.custom.images = data.data;
this.options.custom.showImage.call(this);
}
});
feed.run();
$(".next").click(function () {
var length, current;
current = feed.options.custom.currentImage;
length = feed.options.custom.images.length;
if (current < length - 1) {
feed.options.custom.currentImage++;
feed.options.custom.showImage.call(feed);
}
});
$(".prev").click(function () {
var length, current;
current = feed.options.custom.currentImage;
length = feed.options.custom.images.length;
if (current > 0) {
feed.options.custom.currentImage--
feed.options.custom.showImage.call(feed);
}
});
My HTML:
<div id="instafeed"></div>
<div class="controls">
<div class="prev"><- prev</div>
<div class="next">next -></div>
</div>
The Instafeed.js code:
(function() { var Instafeed, root; Instafeed = (function() {
function Instafeed(params) {
var option, value;
this.options = {
target: 'instafeed',
get: 'popular',
resolution: 'thumbnail',
sortBy: 'most-recent',
links: true,
limit: 15,
mock: false
};
if (typeof params === 'object') {
for (option in params) {
value = params[option];
this.options[option] = value;
}
}
this.unique = this._genKey();
}
Instafeed.prototype.run = function() {
var header, instanceName, script;
if (typeof this.options.clientId !== 'string') {
if (typeof this.options.accessToken !== 'string') {
throw new Error("Missing clientId or accessToken.");
}
}
if (typeof this.options.accessToken !== 'string') {
if (typeof this.options.clientId !== 'string') {
throw new Error("Missing clientId or accessToken.");
}
}
if ((this.options.before != null) && typeof this.options.before === 'function') {
this.options.before.call(this);
}
if (typeof document !== "undefined" && document !== null) {
script = document.createElement('script');
script.id = 'instafeed-fetcher';
script.src = this._buildUrl();
header = document.getElementsByTagName('head');
header[0].appendChild(script);
instanceName = "instafeedCache" + this.unique;
window[instanceName] = new Instafeed(this.options);
window[instanceName].unique = this.unique;
}
return true;
};
Instafeed.prototype.parse = function(response) {
var anchor, fragment, header, htmlString, image, imageString, images, img, instanceName, reverse, sortSettings, _i, _j, _len, _len1;
if (typeof response !== 'object') {
if ((this.options.error != null) && typeof this.options.error === 'function') {
this.options.error.call(this, 'Invalid JSON data');
return false;
} else {
throw new Error('Invalid JSON response');
}
}
if (response.meta.code !== 200) {
if ((this.options.error != null) && typeof this.options.error === 'function') {
this.options.error.call(this, response.meta.error_message);
return false;
} else {
throw new Error("Error from Instagram: " + response.meta.error_message);
}
}
if (response.data.length === 0) {
if ((this.options.error != null) && typeof this.options.error === 'function') {
this.options.error.call(this, 'No images were returned from Instagram');
return false;
} else {
throw new Error('No images were returned from Instagram');
}
}
if ((this.options.success != null) && typeof this.options.success === 'function') {
this.options.success.call(this, response);
}
if (this.options.sortBy !== 'most-recent') {
if (this.options.sortBy === 'random') {
sortSettings = ['', 'random'];
} else {
sortSettings = this.options.sortBy.split('-');
}
reverse = sortSettings[0] === 'least' ? true : false;
switch (sortSettings[1]) {
case 'random':
response.data.sort(function() {
return 0.5 - Math.random();
});
break;
case 'recent':
response.data = this._sortBy(response.data, 'created_time', reverse);
break;
case 'liked':
response.data = this._sortBy(response.data, 'likes.count', reverse);
break;
case 'commented':
response.data = this._sortBy(response.data, 'comments.count', reverse);
break;
default:
throw new Error("Invalid option for sortBy: '" + this.options.sortBy + "'.");
}
}
if ((typeof document !== "undefined" && document !== null) && this.options.mock === false) {
document.getElementById(this.options.target).innerHTML = '';
images = response.data;
if (images.length > this.options.limit) {
images = images.slice(0, this.options.limit + 1 || 9e9);
}
if ((this.options.template != null) && typeof this.options.template === 'string') {
htmlString = '';
imageString = '';
for (_i = 0, _len = images.length; _i < _len; _i++) {
image = images[_i];
imageString = this._makeTemplate(this.options.template, {
model: image,
id: image.id,
link: image.link,
image: image.images[this.options.resolution].url,
caption: this._getObjectProperty(image, 'caption.text'),
likes: image.likes.count,
comments: image.comments.count,
location: this._getObjectProperty(image, 'location.name')
});
htmlString += imageString;
}
document.getElementById(this.options.target).innerHTML = htmlString;
} else {
fragment = document.createDocumentFragment();
for (_j = 0, _len1 = images.length; _j < _len1; _j++) {
image = images[_j];
img = document.createElement('img');
img.src = image.images[this.options.resolution].url;
if (this.options.links === true) {
anchor = document.createElement('a');
anchor.href = image.images['standard_resolution'].url;
anchor.rel = "lightbox";
anchor.appendChild(img);
fragment.appendChild(anchor);
} else {
fragment.appendChild(img);
}
}
document.getElementById(this.options.target).appendChild(fragment);
}
header = document.getElementsByTagName('head')[0];
header.removeChild(document.getElementById('instafeed-fetcher'));
instanceName = "instafeedCache" + this.unique;
delete window[instanceName];
}
if ((this.options.after != null) && typeof this.options.after === 'function') {
this.options.after.call(this);
}
return true;
};
Instafeed.prototype._buildUrl = function() {
var base, endpoint, final;
base = "https://api.instagram.com/v1";
switch (this.options.get) {
case "popular":
endpoint = "media/popular";
break;
case "tagged":
if (typeof this.options.tagName !== 'string') {
throw new Error("No tag name specified. Use the 'tagName' option.");
}
endpoint = "tags/" + this.options.tagName + "/media/recent";
break;
case "location":
if (typeof this.options.locationId !== 'number') {
throw new Error("No location specified. Use the 'locationId' option.");
}
endpoint = "locations/" + this.options.locationId + "/media/recent";
break;
case "user":
if (typeof this.options.userId !== 'number') {
throw new Error("No user specified. Use the 'userId' option.");
}
if (typeof this.options.accessToken !== 'string') {
throw new Error("No access token. Use the 'accessToken' option.");
}
endpoint = "users/" + this.options.userId + "/media/recent";
break;
default:
throw new Error("Invalid option for get: '" + this.options.get + "'.");
}
final = "" + base + "/" + endpoint;
if (this.options.accessToken != null) {
final += "?access_token=" + this.options.accessToken;
} else {
final += "?client_id=" + this.options.clientId;
}
final += "&count=" + this.options.limit;
final += "&callback=instafeedCache" + this.unique + ".parse";
return final;
};
Instafeed.prototype._genKey = function() {
var S4;
S4 = function() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
};
return "" + (S4()) + (S4()) + (S4()) + (S4());
};
Instafeed.prototype._makeTemplate = function(template, data) {
var output, pattern, varName, varValue, _ref;
pattern = /(?:\{{2})([\w\[\]\.]+)(?:\}{2})/;
output = template;
while (pattern.test(output)) {
varName = output.match(pattern)[1];
varValue = (_ref = this._getObjectProperty(data, varName)) != null ? _ref : '';
output = output.replace(pattern, "" + varValue);
}
return output;
};
Instafeed.prototype._getObjectProperty = function(object, property) {
var piece, pieces;
property = property.replace(/\[(\w+)\]/g, '.$1');
pieces = property.split('.');
while (pieces.length) {
piece = pieces.shift();
if ((object != null) && piece in object) {
object = object[piece];
} else {
return null;
}
}
return object;
};
Instafeed.prototype._sortBy = function(data, property, reverse) {
var sorter;
sorter = function(a, b) {
var valueA, valueB;
valueA = this._getObjectProperty(a, property);
valueB = this._getObjectProperty(b, property);
if (reverse) {
if (valueA > valueB) {
return 1;
} else {
return -1;
}
}
if (valueA < valueB) {
return 1;
} else {
return -1;
}
};
data.sort(sorter.bind(this));
return data;
};
return Instafeed;})(); root = typeof exports !== "undefined" && exports !== null ? exports : window; root.Instafeed = Instafeed;}).call(this);
Any help with this issue would be GREATLY appreciated.
Thank You,
Jason