').append(
99 | $('').text(i+1),
100 | $(' ').text(item.Uploader),
101 | $(' ').text(item.Count)
102 | ).appendTo(selecter);
103 |
104 | });
105 | });
106 |
107 |
108 |
109 | }
110 |
111 | function drawLegendChart(dataset,selecter){
112 |
113 | var dataset = $.parseJSON(dataset);
114 | var width = 360;
115 | var height = 360;
116 | var radius = Math.min(width, height) / 2;
117 | var donutWidth = 75;
118 | var legendRectSize = 18;
119 | var legendSpacing = 4;
120 |
121 | var color = d3.scale.category20b();
122 |
123 | var svg = d3.select(selecter)
124 | .append('svg')
125 | .attr('width', width)
126 | .attr('height', height)
127 | .append('g')
128 | .attr('transform', 'translate(' + (width / 2) +
129 | ',' + (height / 2) + ')');
130 |
131 | var arc = d3.svg.arc()
132 | .innerRadius(radius - donutWidth)
133 | .outerRadius(radius);
134 |
135 | var pie = d3.layout.pie()
136 | .value(function(d) { return Number(d.Count); })
137 | .sort(null);
138 |
139 | var path = svg.selectAll('path')
140 | .data(pie(dataset))
141 | .enter()
142 | .append('path')
143 | .attr('d', arc)
144 | .attr('fill', function(d, i) {
145 | return color(d.data.Category);
146 | });
147 |
148 | var legend = svg.selectAll('.legend')
149 | .data(color.domain())
150 | .enter()
151 | .append('g')
152 | .attr('class', 'legend')
153 | .attr('transform', function(d, i) {
154 | var height = legendRectSize + legendSpacing;
155 | var offset = height * color.domain().length / 2;
156 | var horz = -2 * legendRectSize;
157 | var vert = i * height - offset;
158 | return 'translate(' + horz + ',' + vert + ')';
159 | });
160 |
161 | legend.append('rect')
162 | .attr('width', legendRectSize)
163 | .attr('height', legendRectSize)
164 | .style('fill', color)
165 | .style('stroke', color);
166 |
167 | legend.append('text')
168 | .attr('x', legendRectSize + legendSpacing)
169 | .attr('y', legendRectSize - legendSpacing)
170 | .text(function(d) { return d; });
171 |
172 |
173 | }
174 |
175 | function drawHorizontalChart(data,selecter){
176 |
177 |
178 | var tabdata = $.parseJSON(data);
179 |
180 | var colors = ['#0000b4','#0082ca','#0094ff','#0d4bcf','#79BCBF'];
181 | var w = 800,
182 | h = 400;
183 |
184 | var svg = d3.select(selecter)
185 | .append("svg")
186 | .attr("width", w)
187 | .attr("height", h);
188 |
189 |
190 | var max_n = 0;
191 | for (var d in tabdata) {
192 | max_n = Math.max(Number(tabdata[d].Count), max_n);
193 | }
194 |
195 | var dx = w / max_n;
196 | var dy = h / tabdata.length;
197 |
198 | var colorScale = d3.scale.quantize()
199 | .domain([0,tabdata.length])
200 | .range(colors);
201 |
202 | // bars
203 | var bars = svg.selectAll(".bar")
204 | .data(tabdata)
205 | .enter()
206 | .append("rect")
207 | .attr("class", function(d, i) {return "bar " + d.Title;})
208 | .attr("x", function(d, i) {return 0;})
209 | .attr("y", function(d, i) {return dy*i;})
210 | .style('fill',function(d,i){ return colorScale(i); })
211 | .attr("width", function(d, i) {return dx*Number(d.Count)})
212 | .attr("height", dy);
213 |
214 | // labels
215 | var text = svg.selectAll("text")
216 | .data(tabdata)
217 | .enter()
218 | .append("text")
219 | .attr("class", function(d, i) {return "label " + d.Title;})
220 | .attr("x", 2)
221 | .attr("y", function(d, i) {return dy*i + 15;})
222 | .text( function(d) {return d.Title + " ( Views: " + d.Count + ")";})
223 | .attr("font-size", "12px")
224 | .style("font-weight", "bold");
225 |
226 |
227 |
228 |
229 |
230 | }
231 | }
232 |
--------------------------------------------------------------------------------
/WebContent/public/assets/js/skel.min.js:
--------------------------------------------------------------------------------
1 | /* skel.js v3.0.1 | (c) skel.io | MIT licensed */
2 | var skel=function(){"use strict";var t={breakpointIds:null,events:{},isInit:!1,obj:{attachments:{},breakpoints:{},head:null,states:{}},sd:"/",state:null,stateHandlers:{},stateId:"",vars:{},DOMReady:null,indexOf:null,isArray:null,iterate:null,matchesMedia:null,extend:function(e,n){t.iterate(n,function(i){t.isArray(n[i])?(t.isArray(e[i])||(e[i]=[]),t.extend(e[i],n[i])):"object"==typeof n[i]?("object"!=typeof e[i]&&(e[i]={}),t.extend(e[i],n[i])):e[i]=n[i]})},newStyle:function(t){var e=document.createElement("style");return e.type="text/css",e.innerHTML=t,e},_canUse:null,canUse:function(e){t._canUse||(t._canUse=document.createElement("div"));var n=t._canUse.style,i=e.charAt(0).toUpperCase()+e.slice(1);return e in n||"Moz"+i in n||"Webkit"+i in n||"O"+i in n||"ms"+i in n},on:function(e,n){var i=e.split(/[\s]+/);return t.iterate(i,function(e){var a=i[e];if(t.isInit){if("init"==a)return void n();if("change"==a)n();else{var r=a.charAt(0);if("+"==r||"!"==r){var o=a.substring(1);if(o in t.obj.breakpoints)if("+"==r&&t.obj.breakpoints[o].active)n();else if("!"==r&&!t.obj.breakpoints[o].active)return void n()}}}t.events[a]||(t.events[a]=[]),t.events[a].push(n)}),t},trigger:function(e){return t.events[e]&&0!=t.events[e].length?(t.iterate(t.events[e],function(n){t.events[e][n]()}),t):void 0},breakpoint:function(e){return t.obj.breakpoints[e]},breakpoints:function(e){function n(t,e){this.name=this.id=t,this.media=e,this.active=!1,this.wasActive=!1}return n.prototype.matches=function(){return t.matchesMedia(this.media)},n.prototype.sync=function(){this.wasActive=this.active,this.active=this.matches()},t.iterate(e,function(i){t.obj.breakpoints[i]=new n(i,e[i])}),window.setTimeout(function(){t.poll()},0),t},addStateHandler:function(e,n){t.stateHandlers[e]=n},callStateHandler:function(e){var n=t.stateHandlers[e]();t.iterate(n,function(e){t.state.attachments.push(n[e])})},changeState:function(e){t.iterate(t.obj.breakpoints,function(e){t.obj.breakpoints[e].sync()}),t.vars.lastStateId=t.stateId,t.stateId=e,t.breakpointIds=t.stateId===t.sd?[]:t.stateId.substring(1).split(t.sd),t.obj.states[t.stateId]?t.state=t.obj.states[t.stateId]:(t.obj.states[t.stateId]={attachments:[]},t.state=t.obj.states[t.stateId],t.iterate(t.stateHandlers,t.callStateHandler)),t.detachAll(t.state.attachments),t.attachAll(t.state.attachments),t.vars.stateId=t.stateId,t.vars.state=t.state,t.trigger("change"),t.iterate(t.obj.breakpoints,function(e){t.obj.breakpoints[e].active?t.obj.breakpoints[e].wasActive||t.trigger("+"+e):t.obj.breakpoints[e].wasActive&&t.trigger("-"+e)})},generateStateConfig:function(e,n){var i={};return t.extend(i,e),t.iterate(t.breakpointIds,function(e){t.extend(i,n[t.breakpointIds[e]])}),i},getStateId:function(){var e="";return t.iterate(t.obj.breakpoints,function(n){var i=t.obj.breakpoints[n];i.matches()&&(e+=t.sd+i.id)}),e},poll:function(){var e="";e=t.getStateId(),""===e&&(e=t.sd),e!==t.stateId&&t.changeState(e)},_attach:null,attach:function(e){var n=t.obj.head,i=e.element;return i.parentNode&&i.parentNode.tagName?!1:(t._attach||(t._attach=n.firstChild),n.insertBefore(i,t._attach.nextSibling),e.permanent&&(t._attach=i),!0)},attachAll:function(e){var n=[];t.iterate(e,function(t){n[e[t].priority]||(n[e[t].priority]=[]),n[e[t].priority].push(e[t])}),n.reverse(),t.iterate(n,function(e){t.iterate(n[e],function(i){t.attach(n[e][i])})})},detach:function(t){var e=t.element;return t.permanent||!e.parentNode||e.parentNode&&!e.parentNode.tagName?!1:(e.parentNode.removeChild(e),!0)},detachAll:function(e){var n={};t.iterate(e,function(t){n[e[t].id]=!0}),t.iterate(t.obj.attachments,function(e){e in n||t.detach(t.obj.attachments[e])})},attachment:function(e){return e in t.obj.attachments?t.obj.attachments[e]:null},newAttachment:function(e,n,i,a){return t.obj.attachments[e]={id:e,element:n,priority:i,permanent:a}},init:function(){t.initMethods(),t.initVars(),t.initEvents(),t.obj.head=document.getElementsByTagName("head")[0],t.isInit=!0,t.trigger("init")},initEvents:function(){t.on("resize",function(){t.poll()}),t.on("orientationChange",function(){t.poll()}),t.DOMReady(function(){t.trigger("ready")}),window.onload&&t.on("load",window.onload),window.onload=function(){t.trigger("load")},window.onresize&&t.on("resize",window.onresize),window.onresize=function(){t.trigger("resize")},window.onorientationchange&&t.on("orientationChange",window.onorientationchange),window.onorientationchange=function(){t.trigger("orientationChange")}},initMethods:function(){document.addEventListener?!function(e,n){t.DOMReady=n()}("domready",function(){function t(t){for(r=1;t=n.shift();)t()}var e,n=[],i=document,a="DOMContentLoaded",r=/^loaded|^c/.test(i.readyState);return i.addEventListener(a,e=function(){i.removeEventListener(a,e),t()}),function(t){r?t():n.push(t)}}):!function(e,n){t.DOMReady=n()}("domready",function(t){function e(t){for(h=1;t=i.shift();)t()}var n,i=[],a=!1,r=document,o=r.documentElement,s=o.doScroll,c="DOMContentLoaded",d="addEventListener",u="onreadystatechange",l="readyState",f=s?/^loaded|^c/:/^loaded|c/,h=f.test(r[l]);return r[d]&&r[d](c,n=function(){r.removeEventListener(c,n,a),e()},a),s&&r.attachEvent(u,n=function(){/^c/.test(r[l])&&(r.detachEvent(u,n),e())}),t=s?function(e){self!=top?h?e():i.push(e):function(){try{o.doScroll("left")}catch(n){return setTimeout(function(){t(e)},50)}e()}()}:function(t){h?t():i.push(t)}}),Array.prototype.indexOf?t.indexOf=function(t,e){return t.indexOf(e)}:t.indexOf=function(t,e){if("string"==typeof t)return t.indexOf(e);var n,i,a=e?e:0;if(!this)throw new TypeError;if(i=this.length,0===i||a>=i)return-1;for(0>a&&(a=i-Math.abs(a)),n=a;i>n;n++)if(this[n]===t)return n;return-1},Array.isArray?t.isArray=function(t){return Array.isArray(t)}:t.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)},Object.keys?t.iterate=function(t,e){if(!t)return[];var n,i=Object.keys(t);for(n=0;i[n]&&e(i[n],t[i[n]])!==!1;n++);}:t.iterate=function(t,e){if(!t)return[];var n;for(n in t)if(Object.prototype.hasOwnProperty.call(t,n)&&e(n,t[n])===!1)break},window.matchMedia?t.matchesMedia=function(t){return""==t?!0:window.matchMedia(t).matches}:window.styleMedia||window.media?t.matchesMedia=function(t){if(""==t)return!0;var e=window.styleMedia||window.media;return e.matchMedium(t||"all")}:window.getComputedStyle?t.matchesMedia=function(t){if(""==t)return!0;var e=document.createElement("style"),n=document.getElementsByTagName("script")[0],i=null;e.type="text/css",e.id="matchmediajs-test",n.parentNode.insertBefore(e,n),i="getComputedStyle"in window&&window.getComputedStyle(e,null)||e.currentStyle;var a="@media "+t+"{ #matchmediajs-test { width: 1px; } }";return e.styleSheet?e.styleSheet.cssText=a:e.textContent=a,"1px"===i.width}:t.matchesMedia=function(t){if(""==t)return!0;var e,n,i,a,r={"min-width":null,"max-width":null},o=!1;for(i=t.split(/\s+and\s+/),e=0;er["max-width"]||null!==r["min-height"]&&cr["max-height"]?!1:!0},navigator.userAgent.match(/MSIE ([0-9]+)/)&&RegExp.$1<9&&(t.newStyle=function(t){var e=document.createElement("span");return e.innerHTML=' ",e})},initVars:function(){var e,n,i,a=navigator.userAgent;e="other",n=0,i=[["firefox",/Firefox\/([0-9\.]+)/],["bb",/BlackBerry.+Version\/([0-9\.]+)/],["bb",/BB[0-9]+.+Version\/([0-9\.]+)/],["opera",/OPR\/([0-9\.]+)/],["opera",/Opera\/([0-9\.]+)/],["edge",/Edge\/([0-9\.]+)/],["safari",/Version\/([0-9\.]+).+Safari/],["chrome",/Chrome\/([0-9\.]+)/],["ie",/MSIE ([0-9]+)/],["ie",/Trident\/.+rv:([0-9]+)/]],t.iterate(i,function(t,i){return a.match(i[1])?(e=i[0],n=parseFloat(RegExp.$1),!1):void 0}),t.vars.browser=e,t.vars.browserVersion=n,e="other",n=0,i=[["ios",/([0-9_]+) like Mac OS X/,function(t){return t.replace("_",".").replace("_","")}],["ios",/CPU like Mac OS X/,function(t){return 0}],["wp",/Windows Phone ([0-9\.]+)/,null],["android",/Android ([0-9\.]+)/,null],["mac",/Macintosh.+Mac OS X ([0-9_]+)/,function(t){return t.replace("_",".").replace("_","")}],["windows",/Windows NT ([0-9\.]+)/,null],["bb",/BlackBerry.+Version\/([0-9\.]+)/,null],["bb",/BB[0-9]+.+Version\/([0-9\.]+)/,null]],t.iterate(i,function(t,i){return a.match(i[1])?(e=i[0],n=parseFloat(i[2]?i[2](RegExp.$1):RegExp.$1),!1):void 0}),t.vars.os=e,t.vars.osVersion=n,t.vars.IEVersion="ie"==t.vars.browser?t.vars.browserVersion:99,t.vars.touch="wp"==t.vars.os?navigator.msMaxTouchPoints>0:!!("ontouchstart"in window),t.vars.mobile="wp"==t.vars.os||"android"==t.vars.os||"ios"==t.vars.os||"bb"==t.vars.os}};return t.init(),t}();!function(t,e){"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?module.exports=e():t.skel=e()}(this,function(){return skel});
3 |
--------------------------------------------------------------------------------
/WebContent/controllers/searchapi.js:
--------------------------------------------------------------------------------
1 | var youtube = require('youtube-api');
2 | var async = require('async');
3 | var fs = require('fs');
4 | var os = require("os");
5 | var json2csv = require('json2csv');
6 | var finalResults = [];
7 | var inputObject = {};
8 | var count = 0;
9 | var publishAfterTime = '';
10 | var publishBeforeTime = '';
11 |
12 | var API_ACCESS_KEY = 'AIzaSyD93zoVXfwOKmkxMFU0LWKvkdzQMdm1yOk';
13 |
14 | var nextPageToken;
15 |
16 | exports.clickedSearchButton = function(time,done){
17 |
18 | youtube.authenticate({
19 | type: 'key',
20 | key: API_ACCESS_KEY,
21 | });
22 | finalResults = [];
23 | count = 0;
24 | inputObject = {};
25 | inputObject.inputTimeWindow = time;
26 | if (fs.existsSync('data.csv')) {
27 | fs.unlinkSync('data.csv');
28 | }
29 | search(null,done);
30 |
31 | }
32 |
33 | function search(pageToken,mycall) {
34 |
35 | getPublishBeforeAndAfterTime();
36 | var requestOptions = {
37 | type: 'playlist',
38 | part: 'snippet',
39 | q: '',
40 | maxResults: '50',
41 | publishedAfter: publishAfterTime,
42 | publishedBefore: publishBeforeTime
43 | }
44 | if (pageToken) {
45 | requestOptions.pageToken = pageToken;
46 | }
47 |
48 | var request = youtube.search.list(requestOptions,function(err,response){
49 | if (err) return console.log("error");
50 | var resultsArr = [];
51 | nextPageToken = response.nextPageToken;
52 | for(var x in response.items){
53 | var playlistResult = new Object();
54 | playlistResult.playlistId = response.items[x].id.playlistId;
55 | resultsArr.push(playlistResult)
56 | }
57 | for (var i = 0; i < resultsArr.length; i++) {
58 | finalResults.push(resultsArr[i]);
59 | }
60 | if(nextPageToken){
61 | search(nextPageToken,mycall);
62 | }else{
63 | getVideoDetails(function(data){
64 | mycall("success");
65 | });
66 | }
67 | });
68 | }
69 |
70 | function getVideoDetails(callback){
71 |
72 | var i =0 ;
73 | async.whilst(
74 | function(){ return i tag OR Just update it by replacing localhost with master
136 |
137 |
138 |
139 | fs.default.name
140 |
141 | hdfs://HadoopMaster:9000
142 |
143 |
144 |
145 |
146 | ### Update hdfs-site.xml
147 |
148 | Update this file by updating repliction factor from 1 to 3.
149 |
150 |
151 | To edit file, fire the below given command
152 |
153 | `ubuntu@hadoopmaster1:/opt/hadoop/etc/hadoop$ sudo gedit hdfs-site.xml`
154 |
155 |
156 | Paste/Update these lines into tag
157 |
158 |
159 |
160 | dfs.replication
161 |
162 | 3
163 |
164 |
165 |
166 |
167 | ### Update yarn-site.xml
168 |
169 | Update this file by updating the following three properties by updating hostname from localhost to HadoopMaster
170 |
171 |
172 | To edit file, fire the below given command
173 |
174 | `ubuntu@hadoopmaster1:/opt/hadoop/etc/hadoop$ sudo gedit yarn-site.xml`
175 |
176 |
177 | Paste/Update these lines into tag
178 |
179 |
180 |
181 | yarn.resourcemanager.resource-tracker.address
182 |
183 | HadoopMaster:8025
184 |
185 |
186 |
187 |
188 |
189 | yarn.resourcemanager.scheduler.address
190 |
191 | HadoopMaster:8035
192 |
193 |
194 |
195 |
196 |
197 | yarn.resourcemanager.address
198 |
199 | HadoopMaster:8050
200 |
201 |
202 |
203 |
204 | ### Update Mapred-site.xml
205 |
206 | Update this file by updating and adding following properties,
207 |
208 |
209 | To edit file, fire the below given command
210 |
211 | `ubuntu@hadoopmaster1:/opt/hadoop/etc/hadoop$ sudo gedit mapred-site.xml`
212 |
213 |
214 | Paste/Update these lines into tag
215 |
216 |
217 |
218 | mapreduce.job.tracker
219 |
220 | HadoopMaster:5431
221 |
222 |
223 |
224 |
225 |
226 | mapred.framework.name
227 |
228 | yarn
229 |
230 |
231 |
232 |
233 | ### Update slaves
234 |
235 | Update the directory of slave nodes of Hadoop cluster
236 |
237 |
238 | To edit file, fire the below given command
239 |
240 | `ubuntu@hadoopmaster1:/opt/hadoop/etc/hadoop$ sudo gedit slaves`
241 |
242 |
243 | ### Add name of slave nodes
244 |
245 | hadoopslave1
246 | hadoopslave2
247 | hadoopslave3
248 |
249 |
250 | ### Format Namenonde (Run on MasterNode) :
251 |
252 | Run this command from Masternode
253 |
254 | ubuntu@hadoopmaster1: /opt/hadoop/$ hdfs namenode -format
255 |
256 |
257 | ### Copy Hadoop distribution to other nodes:
258 |
259 | `sudo scp -R /opt/hadoop/ ubuntu@hadoopslave1:/opt/`
260 |
261 | `sudo scp -R /opt/hadoop/ ubuntu@hadoopslave2:/opt/`
262 |
263 | `sudo scp -R /opt/hadoop/ ubuntu@hadoopslave3:/opt/`
264 |
265 |
266 | ### Starting Namenode, Datanode and ResourceManger:
267 |
268 | `start-all.sh`
269 |
270 |
271 | ### Check if Hadoop started as desired using jps command.
272 |
273 |
274 | ## Obtaining Youtube API access key
275 |
276 | Use the following link to obtain an API access key.
277 |
278 | https://youtu.be/JbWnRhHfTDA
279 |
280 | ## Install Node.js and node package manager
281 |
282 |
283 | `sudo apt-get update`
284 |
285 | `sudo apt-get install nodejs`
286 |
287 | `sudo apt-get install npm`
288 |
289 |
290 | After installing node.js and npm go to WebContent folder and run the below command to download all the dependencies.
291 |
292 |
293 | `npm install`
294 |
295 |
296 | ## Run The Project
297 |
298 | Run the nodejs server using the command.
299 |
300 | `cd YouTube-Data-Analysis/WebContent/`
301 |
302 | `nodejs app.js`
303 |
304 | The project will be up and running at port `http://localhost:8080`
305 |
306 | Click on `Get More Data` option on the sidebar to get new data via the YouTube API. After the data is stored in the server, a script will run in background to store the data in Hadoop File system.
307 |
308 | Click on `Statistics` option on the sidebar to run the Hadoop MapReduce algorithm on the data. The `Analyze data` button will run the script to start hadoop MapReduce algorithm. The result will be displayed on the same webpage.
309 |
310 | ## Description of each file
311 |
312 | Filename | Purpose | New/Modified | Comments
313 | ------------- | ----------------|------------------ | ----------
314 | YoutubeCategory.java | Mapper Reducer code to get top 5 categories | New | Create JAR of this file to run in Hadoop system
315 | YoutubeUploader.java | Mapper Reducer code to get top uploaders | New | Create JAR of this file to run in Hadoop system
316 | YoutubeView.java | Mapper Reducer code to get most viewed videos | New | Create JAR of this file to run in Hadoop system
317 | analyzedata.sh | Shell script to execute Hadoop commands | New | Merged Sorting commands in the file
318 | getdata.sh | Shell script to copy the data file from server to HDFS | New | No Comments
319 | app.js | Main configuration file to run the entire application | Modified | Changed client server communication from AJAX to socket.io
320 | searchapi.js | Connect to YouTube data API to fetch data in a file | Modified | Changed callbacks and data to be fetched
--------------------------------------------------------------------------------
/WebContent/public/assets/js/util.js:
--------------------------------------------------------------------------------
1 | (function($) {
2 |
3 | /**
4 | * Generate an indented list of links from a nav. Meant for use with panel().
5 | * @return {jQuery} jQuery object.
6 | */
7 | $.fn.navList = function() {
8 |
9 | var $this = $(this);
10 | $a = $this.find('a'),
11 | b = [];
12 |
13 | $a.each(function() {
14 |
15 | var $this = $(this),
16 | indent = Math.max(0, $this.parents('li').length - 1),
17 | href = $this.attr('href'),
18 | target = $this.attr('target');
19 |
20 | b.push(
21 | '' +
26 | ' ' +
27 | $this.text() +
28 | ' '
29 | );
30 |
31 | });
32 |
33 | return b.join('');
34 |
35 | };
36 |
37 | /**
38 | * Panel-ify an element.
39 | * @param {object} userConfig User config.
40 | * @return {jQuery} jQuery object.
41 | */
42 | $.fn.panel = function(userConfig) {
43 |
44 | // No elements?
45 | if (this.length == 0)
46 | return $this;
47 |
48 | // Multiple elements?
49 | if (this.length > 1) {
50 |
51 | for (var i=0; i < this.length; i++)
52 | $(this[i]).panel(userConfig);
53 |
54 | return $this;
55 |
56 | }
57 |
58 | // Vars.
59 | var $this = $(this),
60 | $body = $('body'),
61 | $window = $(window),
62 | id = $this.attr('id'),
63 | config;
64 |
65 | // Config.
66 | config = $.extend({
67 |
68 | // Delay.
69 | delay: 0,
70 |
71 | // Hide panel on link click.
72 | hideOnClick: false,
73 |
74 | // Hide panel on escape keypress.
75 | hideOnEscape: false,
76 |
77 | // Hide panel on swipe.
78 | hideOnSwipe: false,
79 |
80 | // Reset scroll position on hide.
81 | resetScroll: false,
82 |
83 | // Reset forms on hide.
84 | resetForms: false,
85 |
86 | // Side of viewport the panel will appear.
87 | side: null,
88 |
89 | // Target element for "class".
90 | target: $this,
91 |
92 | // Class to toggle.
93 | visibleClass: 'visible'
94 |
95 | }, userConfig);
96 |
97 | // Expand "target" if it's not a jQuery object already.
98 | if (typeof config.target != 'jQuery')
99 | config.target = $(config.target);
100 |
101 | // Panel.
102 |
103 | // Methods.
104 | $this._hide = function(event) {
105 |
106 | // Already hidden? Bail.
107 | if (!config.target.hasClass(config.visibleClass))
108 | return;
109 |
110 | // If an event was provided, cancel it.
111 | if (event) {
112 |
113 | event.preventDefault();
114 | event.stopPropagation();
115 |
116 | }
117 |
118 | // Hide.
119 | config.target.removeClass(config.visibleClass);
120 |
121 | // Post-hide stuff.
122 | window.setTimeout(function() {
123 |
124 | // Reset scroll position.
125 | if (config.resetScroll)
126 | $this.scrollTop(0);
127 |
128 | // Reset forms.
129 | if (config.resetForms)
130 | $this.find('form').each(function() {
131 | this.reset();
132 | });
133 |
134 | }, config.delay);
135 |
136 | };
137 |
138 | // Vendor fixes.
139 | $this
140 | .css('-ms-overflow-style', '-ms-autohiding-scrollbar')
141 | .css('-webkit-overflow-scrolling', 'touch');
142 |
143 | // Hide on click.
144 | if (config.hideOnClick) {
145 |
146 | $this.find('a')
147 | .css('-webkit-tap-highlight-color', 'rgba(0,0,0,0)');
148 |
149 | $this
150 | .on('click', 'a', function(event) {
151 |
152 | var $a = $(this),
153 | href = $a.attr('href'),
154 | target = $a.attr('target');
155 |
156 | if (!href || href == '#' || href == '' || href == '#' + id)
157 | return;
158 |
159 | // Cancel original event.
160 | event.preventDefault();
161 | event.stopPropagation();
162 |
163 | // Hide panel.
164 | $this._hide();
165 |
166 | // Redirect to href.
167 | window.setTimeout(function() {
168 |
169 | if (target == '_blank')
170 | window.open(href);
171 | else
172 | window.location.href = href;
173 |
174 | }, config.delay + 10);
175 |
176 | });
177 |
178 | }
179 |
180 | // Event: Touch stuff.
181 | $this.on('touchstart', function(event) {
182 |
183 | $this.touchPosX = event.originalEvent.touches[0].pageX;
184 | $this.touchPosY = event.originalEvent.touches[0].pageY;
185 |
186 | })
187 |
188 | $this.on('touchmove', function(event) {
189 |
190 | if ($this.touchPosX === null
191 | || $this.touchPosY === null)
192 | return;
193 |
194 | var diffX = $this.touchPosX - event.originalEvent.touches[0].pageX,
195 | diffY = $this.touchPosY - event.originalEvent.touches[0].pageY,
196 | th = $this.outerHeight(),
197 | ts = ($this.get(0).scrollHeight - $this.scrollTop());
198 |
199 | // Hide on swipe?
200 | if (config.hideOnSwipe) {
201 |
202 | var result = false,
203 | boundary = 20,
204 | delta = 50;
205 |
206 | switch (config.side) {
207 |
208 | case 'left':
209 | result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX > delta);
210 | break;
211 |
212 | case 'right':
213 | result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX < (-1 * delta));
214 | break;
215 |
216 | case 'top':
217 | result = (diffX < boundary && diffX > (-1 * boundary)) && (diffY > delta);
218 | break;
219 |
220 | case 'bottom':
221 | result = (diffX < boundary && diffX > (-1 * boundary)) && (diffY < (-1 * delta));
222 | break;
223 |
224 | default:
225 | break;
226 |
227 | }
228 |
229 | if (result) {
230 |
231 | $this.touchPosX = null;
232 | $this.touchPosY = null;
233 | $this._hide();
234 |
235 | return false;
236 |
237 | }
238 |
239 | }
240 |
241 | // Prevent vertical scrolling past the top or bottom.
242 | if (($this.scrollTop() < 0 && diffY < 0)
243 | || (ts > (th - 2) && ts < (th + 2) && diffY > 0)) {
244 |
245 | event.preventDefault();
246 | event.stopPropagation();
247 |
248 | }
249 |
250 | });
251 |
252 | // Event: Prevent certain events inside the panel from bubbling.
253 | $this.on('click touchend touchstart touchmove', function(event) {
254 | event.stopPropagation();
255 | });
256 |
257 | // Event: Hide panel if a child anchor tag pointing to its ID is clicked.
258 | $this.on('click', 'a[href="#' + id + '"]', function(event) {
259 |
260 | event.preventDefault();
261 | event.stopPropagation();
262 |
263 | config.target.removeClass(config.visibleClass);
264 |
265 | });
266 |
267 | // Body.
268 |
269 | // Event: Hide panel on body click/tap.
270 | $body.on('click touchend', function(event) {
271 | $this._hide(event);
272 | });
273 |
274 | // Event: Toggle.
275 | $body.on('click', 'a[href="#' + id + '"]', function(event) {
276 |
277 | event.preventDefault();
278 | event.stopPropagation();
279 |
280 | config.target.toggleClass(config.visibleClass);
281 |
282 | });
283 |
284 | // Window.
285 |
286 | // Event: Hide on ESC.
287 | if (config.hideOnEscape)
288 | $window.on('keydown', function(event) {
289 |
290 | if (event.keyCode == 27)
291 | $this._hide(event);
292 |
293 | });
294 |
295 | return $this;
296 |
297 | };
298 |
299 | /**
300 | * Apply "placeholder" attribute polyfill to one or more forms.
301 | * @return {jQuery} jQuery object.
302 | */
303 | $.fn.placeholder = function() {
304 |
305 | // Browser natively supports placeholders? Bail.
306 | if (typeof (document.createElement('input')).placeholder != 'undefined')
307 | return $(this);
308 |
309 | // No elements?
310 | if (this.length == 0)
311 | return $this;
312 |
313 | // Multiple elements?
314 | if (this.length > 1) {
315 |
316 | for (var i=0; i < this.length; i++)
317 | $(this[i]).placeholder();
318 |
319 | return $this;
320 |
321 | }
322 |
323 | // Vars.
324 | var $this = $(this);
325 |
326 | // Text, TextArea.
327 | $this.find('input[type=text],textarea')
328 | .each(function() {
329 |
330 | var i = $(this);
331 |
332 | if (i.val() == ''
333 | || i.val() == i.attr('placeholder'))
334 | i
335 | .addClass('polyfill-placeholder')
336 | .val(i.attr('placeholder'));
337 |
338 | })
339 | .on('blur', function() {
340 |
341 | var i = $(this);
342 |
343 | if (i.attr('name').match(/-polyfill-field$/))
344 | return;
345 |
346 | if (i.val() == '')
347 | i
348 | .addClass('polyfill-placeholder')
349 | .val(i.attr('placeholder'));
350 |
351 | })
352 | .on('focus', function() {
353 |
354 | var i = $(this);
355 |
356 | if (i.attr('name').match(/-polyfill-field$/))
357 | return;
358 |
359 | if (i.val() == i.attr('placeholder'))
360 | i
361 | .removeClass('polyfill-placeholder')
362 | .val('');
363 |
364 | });
365 |
366 | // Password.
367 | $this.find('input[type=password]')
368 | .each(function() {
369 |
370 | var i = $(this);
371 | var x = $(
372 | $('')
373 | .append(i.clone())
374 | .remove()
375 | .html()
376 | .replace(/type="password"/i, 'type="text"')
377 | .replace(/type=password/i, 'type=text')
378 | );
379 |
380 | if (i.attr('id') != '')
381 | x.attr('id', i.attr('id') + '-polyfill-field');
382 |
383 | if (i.attr('name') != '')
384 | x.attr('name', i.attr('name') + '-polyfill-field');
385 |
386 | x.addClass('polyfill-placeholder')
387 | .val(x.attr('placeholder')).insertAfter(i);
388 |
389 | if (i.val() == '')
390 | i.hide();
391 | else
392 | x.hide();
393 |
394 | i
395 | .on('blur', function(event) {
396 |
397 | event.preventDefault();
398 |
399 | var x = i.parent().find('input[name=' + i.attr('name') + '-polyfill-field]');
400 |
401 | if (i.val() == '') {
402 |
403 | i.hide();
404 | x.show();
405 |
406 | }
407 |
408 | });
409 |
410 | x
411 | .on('focus', function(event) {
412 |
413 | event.preventDefault();
414 |
415 | var i = x.parent().find('input[name=' + x.attr('name').replace('-polyfill-field', '') + ']');
416 |
417 | x.hide();
418 |
419 | i
420 | .show()
421 | .focus();
422 |
423 | })
424 | .on('keypress', function(event) {
425 |
426 | event.preventDefault();
427 | x.val('');
428 |
429 | });
430 |
431 | });
432 |
433 | // Events.
434 | $this
435 | .on('submit', function() {
436 |
437 | $this.find('input[type=text],input[type=password],textarea')
438 | .each(function(event) {
439 |
440 | var i = $(this);
441 |
442 | if (i.attr('name').match(/-polyfill-field$/))
443 | i.attr('name', '');
444 |
445 | if (i.val() == i.attr('placeholder')) {
446 |
447 | i.removeClass('polyfill-placeholder');
448 | i.val('');
449 |
450 | }
451 |
452 | });
453 |
454 | })
455 | .on('reset', function(event) {
456 |
457 | event.preventDefault();
458 |
459 | $this.find('select')
460 | .val($('option:first').val());
461 |
462 | $this.find('input,textarea')
463 | .each(function() {
464 |
465 | var i = $(this),
466 | x;
467 |
468 | i.removeClass('polyfill-placeholder');
469 |
470 | switch (this.type) {
471 |
472 | case 'submit':
473 | case 'reset':
474 | break;
475 |
476 | case 'password':
477 | i.val(i.attr('defaultValue'));
478 |
479 | x = i.parent().find('input[name=' + i.attr('name') + '-polyfill-field]');
480 |
481 | if (i.val() == '') {
482 | i.hide();
483 | x.show();
484 | }
485 | else {
486 | i.show();
487 | x.hide();
488 | }
489 |
490 | break;
491 |
492 | case 'checkbox':
493 | case 'radio':
494 | i.attr('checked', i.attr('defaultValue'));
495 | break;
496 |
497 | case 'text':
498 | case 'textarea':
499 | i.val(i.attr('defaultValue'));
500 |
501 | if (i.val() == '') {
502 | i.addClass('polyfill-placeholder');
503 | i.val(i.attr('placeholder'));
504 | }
505 |
506 | break;
507 |
508 | default:
509 | i.val(i.attr('defaultValue'));
510 | break;
511 |
512 | }
513 | });
514 |
515 | });
516 |
517 | return $this;
518 |
519 | };
520 |
521 | /**
522 | * Moves elements to/from the first positions of their respective parents.
523 | * @param {jQuery} $elements Elements (or selector) to move.
524 | * @param {bool} condition If true, moves elements to the top. Otherwise, moves elements back to their original locations.
525 | */
526 | $.prioritize = function($elements, condition) {
527 |
528 | var key = '__prioritize';
529 |
530 | // Expand $elements if it's not already a jQuery object.
531 | if (typeof $elements != 'jQuery')
532 | $elements = $($elements);
533 |
534 | // Step through elements.
535 | $elements.each(function() {
536 |
537 | var $e = $(this), $p,
538 | $parent = $e.parent();
539 |
540 | // No parent? Bail.
541 | if ($parent.length == 0)
542 | return;
543 |
544 | // Not moved? Move it.
545 | if (!$e.data(key)) {
546 |
547 | // Condition is false? Bail.
548 | if (!condition)
549 | return;
550 |
551 | // Get placeholder (which will serve as our point of reference for when this element needs to move back).
552 | $p = $e.prev();
553 |
554 | // Couldn't find anything? Means this element's already at the top, so bail.
555 | if ($p.length == 0)
556 | return;
557 |
558 | // Move element to top of parent.
559 | $e.prependTo($parent);
560 |
561 | // Mark element as moved.
562 | $e.data(key, $p);
563 |
564 | }
565 |
566 | // Moved already?
567 | else {
568 |
569 | // Condition is true? Bail.
570 | if (condition)
571 | return;
572 |
573 | $p = $e.data(key);
574 |
575 | // Move element back to its original location (using our placeholder).
576 | $e.insertAfter($p);
577 |
578 | // Unmark element as moved.
579 | $e.removeData(key);
580 |
581 | }
582 |
583 | });
584 |
585 | };
586 |
587 | })(jQuery);
--------------------------------------------------------------------------------
/WebContent/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | true
79 | DEFINITION_ORDER
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 | project
146 |
147 |
148 | true
149 |
150 |
151 |
152 | DIRECTORY
153 |
154 | false
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 | 1476497571596
176 |
177 |
178 | 1476497571596
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
--------------------------------------------------------------------------------
/WebContent/public/assets/sass/libs/_skel.scss:
--------------------------------------------------------------------------------
1 | // skel.scss v3.0.1 | (c) skel.io | MIT licensed */
2 |
3 | // Vars.
4 |
5 | /// Breakpoints.
6 | /// @var {list}
7 | $breakpoints: () !global;
8 |
9 | /// Vendor prefixes.
10 | /// @var {list}
11 | $vendor-prefixes: (
12 | '-moz-',
13 | '-webkit-',
14 | '-ms-',
15 | ''
16 | );
17 |
18 | /// Properties that should be vendorized.
19 | /// @var {list}
20 | $vendor-properties: (
21 | 'align-content',
22 | 'align-items',
23 | 'align-self',
24 | 'animation',
25 | 'animation-delay',
26 | 'animation-direction',
27 | 'animation-duration',
28 | 'animation-fill-mode',
29 | 'animation-iteration-count',
30 | 'animation-name',
31 | 'animation-play-state',
32 | 'animation-timing-function',
33 | 'appearance',
34 | 'backface-visibility',
35 | 'box-sizing',
36 | 'filter',
37 | 'flex',
38 | 'flex-basis',
39 | 'flex-direction',
40 | 'flex-flow',
41 | 'flex-grow',
42 | 'flex-shrink',
43 | 'flex-wrap',
44 | 'justify-content',
45 | 'order',
46 | 'perspective',
47 | 'pointer-events',
48 | 'transform',
49 | 'transform-origin',
50 | 'transform-style',
51 | 'transition',
52 | 'transition-delay',
53 | 'transition-duration',
54 | 'transition-property',
55 | 'transition-timing-function',
56 | 'user-select'
57 | );
58 |
59 | /// Values that should be vendorized.
60 | /// @var {list}
61 | $vendor-values: (
62 | 'filter',
63 | 'flex',
64 | 'linear-gradient',
65 | 'radial-gradient',
66 | 'transform'
67 | );
68 |
69 | // Functions.
70 |
71 | /// Removes a specific item from a list.
72 | /// @author Hugo Giraudel
73 | /// @param {list} $list List.
74 | /// @param {integer} $index Index.
75 | /// @return {list} Updated list.
76 | @function remove-nth($list, $index) {
77 |
78 | $result: null;
79 |
80 | @if type-of($index) != number {
81 | @warn "$index: #{quote($index)} is not a number for `remove-nth`.";
82 | }
83 | @else if $index == 0 {
84 | @warn "List index 0 must be a non-zero integer for `remove-nth`.";
85 | }
86 | @else if abs($index) > length($list) {
87 | @warn "List index is #{$index} but list is only #{length($list)} item long for `remove-nth`.";
88 | }
89 | @else {
90 |
91 | $result: ();
92 | $index: if($index < 0, length($list) + $index + 1, $index);
93 |
94 | @for $i from 1 through length($list) {
95 |
96 | @if $i != $index {
97 | $result: append($result, nth($list, $i));
98 | }
99 |
100 | }
101 |
102 | }
103 |
104 | @return $result;
105 |
106 | }
107 |
108 | /// Replaces a substring within another string.
109 | /// @author Hugo Giraudel
110 | /// @param {string} $string String.
111 | /// @param {string} $search Substring.
112 | /// @param {string} $replace Replacement.
113 | /// @return {string} Updated string.
114 | @function str-replace($string, $search, $replace: '') {
115 |
116 | $index: str-index($string, $search);
117 |
118 | @if $index {
119 | @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
120 | }
121 |
122 | @return $string;
123 |
124 | }
125 |
126 | /// Replaces a substring within each string in a list.
127 | /// @param {list} $strings List of strings.
128 | /// @param {string} $search Substring.
129 | /// @param {string} $replace Replacement.
130 | /// @return {list} Updated list of strings.
131 | @function str-replace-all($strings, $search, $replace: '') {
132 |
133 | @each $string in $strings {
134 | $strings: set-nth($strings, index($strings, $string), str-replace($string, $search, $replace));
135 | }
136 |
137 | @return $strings;
138 |
139 | }
140 |
141 | /// Gets a value from a map.
142 | /// @author Hugo Giraudel
143 | /// @param {map} $map Map.
144 | /// @param {string} $keys Key(s).
145 | /// @return {string} Value.
146 | @function val($map, $keys...) {
147 |
148 | @if nth($keys, 1) == null {
149 | $keys: remove-nth($keys, 1);
150 | }
151 |
152 | @each $key in $keys {
153 | $map: map-get($map, $key);
154 | }
155 |
156 | @return $map;
157 |
158 | }
159 |
160 | // Mixins.
161 |
162 | /// Sets the global box model.
163 | /// @param {string} $model Model (default is content).
164 | @mixin boxModel($model: 'content') {
165 |
166 | $x: $model + '-box';
167 |
168 | *, *:before, *:after {
169 | -moz-box-sizing: #{$x};
170 | -webkit-box-sizing: #{$x};
171 | box-sizing: #{$x};
172 | }
173 |
174 | }
175 |
176 | /// Wraps @content in a @media block using a given breakpoint.
177 | /// @param {string} $breakpoint Breakpoint.
178 | /// @param {map} $queries Additional queries.
179 | @mixin breakpoint($breakpoint: null, $queries: null) {
180 |
181 | $query: 'screen';
182 |
183 | // Breakpoint.
184 | @if $breakpoint and map-has-key($breakpoints, $breakpoint) {
185 | $query: $query + ' and ' + map-get($breakpoints, $breakpoint);
186 | }
187 |
188 | // Queries.
189 | @if $queries {
190 | @each $k, $v in $queries {
191 | $query: $query + ' and (' + $k + ':' + $v + ')';
192 | }
193 | }
194 |
195 | @media #{$query} {
196 | @content;
197 | }
198 |
199 | }
200 |
201 | /// Wraps @content in a @media block targeting a specific orientation.
202 | /// @param {string} $orientation Orientation.
203 | @mixin orientation($orientation) {
204 | @media screen and (orientation: #{$orientation}) {
205 | @content;
206 | }
207 | }
208 |
209 | /// Utility mixin for containers.
210 | /// @param {mixed} $width Width.
211 | @mixin containers($width) {
212 |
213 | // Locked?
214 | $lock: false;
215 |
216 | @if length($width) == 2 {
217 | $width: nth($width, 1);
218 | $lock: true;
219 | }
220 |
221 | // Modifiers.
222 | .container.\31 25\25 { width: 100%; max-width: $width * 1.25; min-width: $width; }
223 | .container.\37 5\25 { width: $width * 0.75; }
224 | .container.\35 0\25 { width: $width * 0.5; }
225 | .container.\32 5\25 { width: $width * 0.25; }
226 |
227 | // Main class.
228 | .container {
229 | @if $lock {
230 | width: $width !important;
231 | }
232 | @else {
233 | width: $width;
234 | }
235 | }
236 |
237 | }
238 |
239 | /// Utility mixin for grid.
240 | /// @param {list} $gutters Column and row gutters (default is 40px).
241 | /// @param {string} $breakpointName Optional breakpoint name.
242 | @mixin grid($gutters: 40px, $breakpointName: null) {
243 |
244 | // Gutters.
245 | @include grid-gutters($gutters);
246 | @include grid-gutters($gutters, \32 00\25, 2);
247 | @include grid-gutters($gutters, \31 50\25, 1.5);
248 | @include grid-gutters($gutters, \35 0\25, 0.5);
249 | @include grid-gutters($gutters, \32 5\25, 0.25);
250 |
251 | // Cells.
252 | $x: '';
253 |
254 | @if $breakpointName {
255 | $x: '\\28' + $breakpointName + '\\29';
256 | }
257 |
258 | .\31 2u#{$x}, .\31 2u\24#{$x} { width: 100%; clear: none; margin-left: 0; }
259 | .\31 1u#{$x}, .\31 1u\24#{$x} { width: 91.6666666667%; clear: none; margin-left: 0; }
260 | .\31 0u#{$x}, .\31 0u\24#{$x} { width: 83.3333333333%; clear: none; margin-left: 0; }
261 | .\39 u#{$x}, .\39 u\24#{$x} { width: 75%; clear: none; margin-left: 0; }
262 | .\38 u#{$x}, .\38 u\24#{$x} { width: 66.6666666667%; clear: none; margin-left: 0; }
263 | .\37 u#{$x}, .\37 u\24#{$x} { width: 58.3333333333%; clear: none; margin-left: 0; }
264 | .\36 u#{$x}, .\36 u\24#{$x} { width: 50%; clear: none; margin-left: 0; }
265 | .\35 u#{$x}, .\35 u\24#{$x} { width: 41.6666666667%; clear: none; margin-left: 0; }
266 | .\34 u#{$x}, .\34 u\24#{$x} { width: 33.3333333333%; clear: none; margin-left: 0; }
267 | .\33 u#{$x}, .\33 u\24#{$x} { width: 25%; clear: none; margin-left: 0; }
268 | .\32 u#{$x}, .\32 u\24#{$x} { width: 16.6666666667%; clear: none; margin-left: 0; }
269 | .\31 u#{$x}, .\31 u\24#{$x} { width: 8.3333333333%; clear: none; margin-left: 0; }
270 |
271 | .\31 2u\24#{$x} + *,
272 | .\31 1u\24#{$x} + *,
273 | .\31 0u\24#{$x} + *,
274 | .\39 u\24#{$x} + *,
275 | .\38 u\24#{$x} + *,
276 | .\37 u\24#{$x} + *,
277 | .\36 u\24#{$x} + *,
278 | .\35 u\24#{$x} + *,
279 | .\34 u\24#{$x} + *,
280 | .\33 u\24#{$x} + *,
281 | .\32 u\24#{$x} + *,
282 | .\31 u\24#{$x} + * {
283 | clear: left;
284 | }
285 |
286 | .\-11u#{$x} { margin-left: 91.6666666667% }
287 | .\-10u#{$x} { margin-left: 83.3333333333% }
288 | .\-9u#{$x} { margin-left: 75% }
289 | .\-8u#{$x} { margin-left: 66.6666666667% }
290 | .\-7u#{$x} { margin-left: 58.3333333333% }
291 | .\-6u#{$x} { margin-left: 50% }
292 | .\-5u#{$x} { margin-left: 41.6666666667% }
293 | .\-4u#{$x} { margin-left: 33.3333333333% }
294 | .\-3u#{$x} { margin-left: 25% }
295 | .\-2u#{$x} { margin-left: 16.6666666667% }
296 | .\-1u#{$x} { margin-left: 8.3333333333% }
297 |
298 | }
299 |
300 | /// Utility mixin for grid.
301 | /// @param {list} $gutters Gutters.
302 | /// @param {string} $class Optional class name.
303 | /// @param {integer} $multiplier Multiplier (default is 1).
304 | @mixin grid-gutters($gutters, $class: null, $multiplier: 1) {
305 |
306 | // Expand gutters if it's not a list.
307 | @if length($gutters) == 1 {
308 | $gutters: ($gutters, 0);
309 | }
310 |
311 | // Get column and row gutter values.
312 | $c: nth($gutters, 1);
313 | $r: nth($gutters, 2);
314 |
315 | // Get class (if provided).
316 | $x: '';
317 |
318 | @if $class {
319 | $x: '.' + $class;
320 | }
321 |
322 | // Default.
323 | .row#{$x} > * { padding: ($r * $multiplier) 0 0 ($c * $multiplier); }
324 | .row#{$x} { margin: ($r * $multiplier * -1) 0 -1px ($c * $multiplier * -1); }
325 |
326 | // Uniform.
327 | .row.uniform#{$x} > * { padding: ($c * $multiplier) 0 0 ($c * $multiplier); }
328 | .row.uniform#{$x} { margin: ($c * $multiplier * -1) 0 -1px ($c * $multiplier * -1); }
329 |
330 | }
331 |
332 | /// Wraps @content in vendorized keyframe blocks.
333 | /// @param {string} $name Name.
334 | @mixin keyframes($name) {
335 |
336 | @-moz-keyframes #{$name} { @content; }
337 | @-webkit-keyframes #{$name} { @content; }
338 | @-ms-keyframes #{$name} { @content; }
339 | @keyframes #{$name} { @content; }
340 |
341 | }
342 |
343 | ///
344 | /// Sets breakpoints.
345 | /// @param {map} $x Breakpoints.
346 | ///
347 | @mixin skel-breakpoints($x: ()) {
348 | $breakpoints: $x !global;
349 | }
350 |
351 | ///
352 | /// Initializes layout module.
353 | /// @param {map} config Config.
354 | ///
355 | @mixin skel-layout($config: ()) {
356 |
357 | // Config.
358 | $configPerBreakpoint: ();
359 |
360 | $z: map-get($config, 'breakpoints');
361 |
362 | @if $z {
363 | $configPerBreakpoint: $z;
364 | }
365 |
366 | // Reset.
367 | $x: map-get($config, 'reset');
368 |
369 | @if $x {
370 |
371 | /* Reset */
372 |
373 | @include reset($x);
374 |
375 | }
376 |
377 | // Box model.
378 | $x: map-get($config, 'boxModel');
379 |
380 | @if $x {
381 |
382 | /* Box Model */
383 |
384 | @include boxModel($x);
385 |
386 | }
387 |
388 | // Containers.
389 | $containers: map-get($config, 'containers');
390 |
391 | @if $containers {
392 |
393 | /* Containers */
394 |
395 | .container {
396 | margin-left: auto;
397 | margin-right: auto;
398 | }
399 |
400 | // Use default is $containers is just "true".
401 | @if $containers == true {
402 | $containers: 960px;
403 | }
404 |
405 | // Apply base.
406 | @include containers($containers);
407 |
408 | // Apply per-breakpoint.
409 | @each $name in map-keys($breakpoints) {
410 |
411 | // Get/use breakpoint setting if it exists.
412 | $x: map-get($configPerBreakpoint, $name);
413 |
414 | // Per-breakpoint config exists?
415 | @if $x {
416 | $y: map-get($x, 'containers');
417 |
418 | // Setting exists? Use it.
419 | @if $y {
420 | $containers: $y;
421 | }
422 |
423 | }
424 |
425 | // Create @media block.
426 | @media screen and #{map-get($breakpoints, $name)} {
427 | @include containers($containers);
428 | }
429 |
430 | }
431 |
432 | }
433 |
434 | // Grid.
435 | $grid: map-get($config, 'grid');
436 |
437 | @if $grid {
438 |
439 | /* Grid */
440 |
441 | // Use defaults if $grid is just "true".
442 | @if $grid == true {
443 | $grid: ();
444 | }
445 |
446 | // Sub-setting: Gutters.
447 | $grid-gutters: 40px;
448 | $x: map-get($grid, 'gutters');
449 |
450 | @if $x {
451 | $grid-gutters: $x;
452 | }
453 |
454 | // Rows.
455 | .row {
456 | border-bottom: solid 1px transparent;
457 | -moz-box-sizing: border-box;
458 | -webkit-box-sizing: border-box;
459 | box-sizing: border-box;
460 | }
461 |
462 | .row > * {
463 | float: left;
464 | -moz-box-sizing: border-box;
465 | -webkit-box-sizing: border-box;
466 | box-sizing: border-box;
467 | }
468 |
469 | .row:after, .row:before {
470 | content: '';
471 | display: block;
472 | clear: both;
473 | height: 0;
474 | }
475 |
476 | .row.uniform > * > :first-child {
477 | margin-top: 0;
478 | }
479 |
480 | .row.uniform > * > :last-child {
481 | margin-bottom: 0;
482 | }
483 |
484 | // Gutters (0%).
485 | @include grid-gutters($grid-gutters, \30 \25, 0);
486 |
487 | // Apply base.
488 | @include grid($grid-gutters);
489 |
490 | // Apply per-breakpoint.
491 | @each $name in map-keys($breakpoints) {
492 |
493 | // Get/use breakpoint setting if it exists.
494 | $x: map-get($configPerBreakpoint, $name);
495 |
496 | // Per-breakpoint config exists?
497 | @if $x {
498 | $y: map-get($x, 'grid');
499 |
500 | // Setting exists?
501 | @if $y {
502 |
503 | // Sub-setting: Gutters.
504 | $x: map-get($y, 'gutters');
505 |
506 | @if $x {
507 | $grid-gutters: $x;
508 | }
509 |
510 | }
511 |
512 | }
513 |
514 | // Create @media block.
515 | @media screen and #{map-get($breakpoints, $name)} {
516 | @include grid($grid-gutters, $name);
517 | }
518 |
519 | }
520 |
521 | }
522 |
523 | }
524 |
525 | /// Resets browser styles.
526 | /// @param {string} $mode Mode (default is 'normalize').
527 | @mixin reset($mode: 'normalize') {
528 |
529 | @if $mode == 'normalize' {
530 |
531 | // normalize.css v3.0.2 | MIT License | git.io/normalize
532 | html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}
533 |
534 | }
535 | @else if $mode == 'full' {
536 |
537 | // meyerweb.com/eric/tools/css/reset v2.0 | 20110126 | License: none (public domain)
538 | html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block;}body{line-height:1;}ol,ul{list-style:none;}blockquote,q{quotes:none;}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none;}table{border-collapse:collapse;border-spacing:0;}body{-webkit-text-size-adjust:none}
539 |
540 | }
541 |
542 | }
543 |
544 | /// Vendorizes a declaration's property and/or value(s).
545 | /// @param {string} $property Property.
546 | /// @param {mixed} $value String/list of value(s).
547 | @mixin vendor($property, $value) {
548 |
549 | // Determine if property should expand.
550 | $expandProperty: index($vendor-properties, $property);
551 |
552 | // Determine if value should expand (and if so, add '-prefix-' placeholder).
553 | $expandValue: false;
554 |
555 | @each $x in $value {
556 | @each $y in $vendor-values {
557 | @if $y == str-slice($x, 1, str-length($y)) {
558 |
559 | $value: set-nth($value, index($value, $x), '-prefix-' + $x);
560 | $expandValue: true;
561 |
562 | }
563 | }
564 | }
565 |
566 | // Expand property?
567 | @if $expandProperty {
568 | @each $vendor in $vendor-prefixes {
569 | #{$vendor}#{$property}: #{str-replace-all($value, '-prefix-', $vendor)};
570 | }
571 | }
572 |
573 | // Expand just the value?
574 | @elseif $expandValue {
575 | @each $vendor in $vendor-prefixes {
576 | #{$property}: #{str-replace-all($value, '-prefix-', $vendor)};
577 | }
578 | }
579 |
580 | // Neither? Treat them as a normal declaration.
581 | @else {
582 | #{$property}: #{$value};
583 | }
584 |
585 | }
--------------------------------------------------------------------------------