Skip to content

Instantly share code, notes, and snippets.

@enatividad
Last active June 24, 2016 11:12
Show Gist options
  • Save enatividad/528943c545ba75935627f2c98daf4d39 to your computer and use it in GitHub Desktop.
Save enatividad/528943c545ba75935627f2c98daf4d39 to your computer and use it in GitHub Desktop.

Directory Structure

app/assets/js

This contains a folder with two sub-folders and one file. It also

  • app/assets/js/app/app.js - contains the App object. It makes functions like initView(), initComponents(), and reinitComponents() available
  • app/assets/js/app/components/ - contatains reusable components only. I don't plan subdirectories.
  • app/assets/js/app/views/ - contains page-specific code. also contains what might be called "page-specific components. copies the directory structure of the app/views like in rails
  • app/assets/js/manifest.js - concatenates all javascript files in the following order:
    1. app/assets/js/app/app.js - contains App object
    2. javascript libraries, manually arranged according to the dependencies of each
    3. app/assets/js/app/components/ folder tree
    4. app/assets/js/app/views folder tree
    5. a small bit of code in app/assets/js/manifest.js to initialize the components and a view through the App object

app/views

This contains the pages to be displayed, and the layouts.

How it works

All components are initialized all at once.

On every page load, jQuery binds event listeners to elements with [data-app-component], whether the element exists or not (I did this this so that it might work better with turbolinks in the future). This components may also create and trigger custom events. Once an event is triggered, the component activates its code.

on every single page
...
<div data-app-component="notifier">
<audio src="{{ url('maramba.mp3') }}"
data-notifier="new-order"
data-url="{{ url('b/orders/newest') }}"
data-title="You have a new order"
data-icon="https://s3-ap-southeast-1.amazonaws.com/elasticbeanstalk-ap-southeast-1-622281270456/Icon-167%402x.png"
></audio>
</div>
...
// create if it doesn't exist yet
this.App = this.App || {};
App.components = App.components || {};
App.views = App.views || {};
// initialization functions
App.initializeComponents = function() {
for (var component in App.components) {
if (App.components.hasOwnProperty(component)) {
App.components[component]();
}
}
};
App.initializeView = function(view) {
view = view || $('[data-app-view]').data('app-view') || null;
if (view !== null && App.views.hasOwnProperty(view)) {
App.views[view]();
}
};
// let us assume everything was already concatenated
// this might also be .on('other:event')
$(document).on('ready', function() {
App.initializeComponents();
});
App.components['notifier'] = function() {
'use strict';
// declare constants
var NAME = 'notifier';
var EVENT_NAME = 'app:notify';
var SELECTOR = '[data-app-component=' + NAME + ']';
var NOTIFIER_SELECTOR = SELECTOR + ' > [data-notifier]';
// binds the ajax requests for each notification type
$(NOTIFIER_SELECTOR).each(function() {
var $object = $(this);
var notification = function() {
$.get($object.data('url'), function(data) {
var response = data.data;
var momentResponse = moment(response["created_at"]);
notification.momentCurrent = notification.momentCurrent || momentResponse;
if (notification.momentCurrent.isBefore(momentResponse)) {
notification.momentCurrent = momentResponse;
$(SELECTOR).trigger(EVENT_NAME, $object.get(0));
}
setTimeout(notification, 5000);
});
};
notification();
});
// if new notifications are available from the server,
// create notifications for each notification type
$(document).on(EVENT_NAME, SELECTOR, function(event, object) {
var $object = $(object);
var title = $object.data('title');
var options = {
dir: $object.data('dir') || 'auto',
lang: $object.data('lang'),
body: $object.data('body'),
// tag: $object.data('tag'),
icon: $object.data('icon'),
data: null,
vibrate: null,
renotify: $object.data('renotify') || false
// requireInteraction: $object.data('require-interaction') || false,
// sticky: $object.data('sticky') || false
};
// show notification immediately
if (Notification.permission === 'granted') {
new Notification(title, options);
}
object.play();
// show notification in intervals afterward
if (Notification.permission === 'granted') {
var notificationInterval = setInterval(function() {
var notification = new Notification(title, options);
object.play();
notification.onclick = function() {
clearInterval(notificationInterval);
};
}, 5000);
}
});
// request permission if not yet granted
if (Notification.permission === 'default') {
Notification.requestPermission();
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment