Path: blob/master/webroot/rsrc/js/application/files/behavior-document-engine.js
12241 views
/**1* @provides javelin-behavior-document-engine2* @requires javelin-behavior3* javelin-dom4* javelin-stratcom5*/67JX.behavior('document-engine', function(config, statics) {89function onmenu(e) {10var node = e.getNode('document-engine-view-dropdown');11var data = JX.Stratcom.getData(node);1213if (data.menu) {14return;15}1617e.prevent();1819var menu = new JX.PHUIXDropdownMenu(node);20var list = new JX.PHUIXActionListView();2122var view;23var engines = [];24for (var ii = 0; ii < data.views.length; ii++) {25var spec = data.views[ii];2627view = new JX.PHUIXActionView()28.setName(spec.name)29.setIcon(spec.icon)30.setIconColor(spec.color)31.setHref(spec.engineURI);3233view.setHandler(JX.bind(null, function(spec, e) {34if (!e.isNormalClick()) {35return;36}3738e.prevent();39menu.close();4041onview(data, spec, false);42}, spec));4344list.addItem(view);4546engines.push({47spec: spec,48view: view49});50}5152list.addItem(53new JX.PHUIXActionView()54.setDivider(true));5556var encode_item = new JX.PHUIXActionView()57.setName(data.encode.name)58.setIcon(data.encode.icon);5960var onencode = JX.bind(null, function(data, e) {61e.prevent();6263if (encode_item.getDisabled()) {64return;65}6667new JX.Workflow(data.encode.uri, {encoding: data.encode.value})68.setHandler(function(r) {69data.encode.value = r.encoding;70onview(data);71})72.start();7374menu.close();7576}, data);7778encode_item.setHandler(onencode);7980list.addItem(encode_item);8182var highlight_item = new JX.PHUIXActionView()83.setName(data.highlight.name)84.setIcon(data.highlight.icon);8586var onhighlight = JX.bind(null, function(data, e) {87e.prevent();8889if (highlight_item.getDisabled()) {90return;91}9293new JX.Workflow(data.highlight.uri, {highlight: data.highlight.value})94.setHandler(function(r) {95data.highlight.value = r.highlight;96onview(data);97})98.start();99100menu.close();101}, data);102103highlight_item.setHandler(onhighlight);104105list.addItem(highlight_item);106107var blame_item;108if (data.blame.uri) {109blame_item = new JX.PHUIXActionView()110.setIcon(data.blame.icon);111112var onblame = JX.bind(null, function(data, e) {113e.prevent();114115if (blame_item.getDisabled()) {116return;117}118119data.blame.enabled = !data.blame.enabled;120onview(data);121122menu.close();123}, data);124125blame_item.setHandler(onblame);126127list.addItem(blame_item);128}129130menu.setContent(list.getNode());131132menu.listen('open', function() {133for (var ii = 0; ii < engines.length; ii++) {134var engine = engines[ii];135136// Highlight the current rendering engine.137var is_selected = (engine.spec.viewKey == data.viewKey);138engine.view.setSelected(is_selected);139140if (is_selected) {141encode_item.setDisabled(!engine.spec.canEncode);142highlight_item.setDisabled(!engine.spec.canHighlight);143if (blame_item) {144blame_item.setDisabled(!engine.spec.canBlame);145}146}147}148149if (blame_item) {150var blame_label;151if (data.blame.enabled) {152blame_label = data.blame.hide;153} else {154blame_label = data.blame.show;155}156157blame_item.setName(blame_label);158}159});160161data.menu = menu;162menu.open();163}164165function add_params(uri, data) {166uri = JX.$U(uri);167168if (data.highlight.value) {169uri.setQueryParam('highlight', data.highlight.value);170}171172if (data.encode.value) {173uri.setQueryParam('encode', data.encode.value);174}175176if (data.blame.enabled) {177uri.setQueryParam('blame', null);178} else {179uri.setQueryParam('blame', 'off');180}181182return uri.toString();183}184185function onview(data, spec, immediate) {186if (!spec) {187for (var ii = 0; ii < data.views.length; ii++) {188if (data.views[ii].viewKey == data.viewKey) {189spec = data.views[ii];190break;191}192}193}194195data.sequence = (data.sequence || 0) + 1;196var handler = JX.bind(null, onrender, data, data.sequence, spec);197198data.viewKey = spec.viewKey;199200var uri = add_params(spec.engineURI, data);201202new JX.Request(uri, handler)203.send();204205if (data.loadingView) {206// If we're already showing "Loading...", immediately change it to207// show the new document type.208onloading(data, spec);209} else if (!immediate) {210// Otherwise, grey out the document and show "Loading..." after a211// short delay. This prevents the content from flickering when rendering212// is fast.213var viewport = JX.$(data.viewportID);214JX.DOM.alterClass(viewport, 'document-engine-in-flight', true);215216var load = JX.bind(null, onloading, data, spec);217data.loadTimer = setTimeout(load, 333);218219// Replace the URI with the URI for the specific rendering the user220// has selected.221222var view_uri = add_params(spec.viewURI, data);223JX.History.replace(view_uri);224}225}226227function onloading(data, spec) {228data.loadingView = true;229230var viewport = JX.$(data.viewportID);231JX.DOM.alterClass(viewport, 'document-engine-in-flight', false);232JX.DOM.setContent(viewport, JX.$H(spec.loadingMarkup));233}234235function onrender(data, sequence, spec, r) {236// If this isn't the most recent request we sent, throw it away. This can237// happen if the user makes multiple selections from the menu while we are238// still rendering the first view.239if (sequence != data.sequence) {240return;241}242243if (data.loadTimer) {244clearTimeout(data.loadTimer);245data.loadTimer = null;246}247248var viewport = JX.$(data.viewportID);249250JX.DOM.alterClass(viewport, 'document-engine-in-flight', false);251data.loadingView = false;252253JX.DOM.setContent(viewport, JX.$H(r.markup));254255// If this engine supports rendering blame, populate or draw it.256if (spec.canBlame && data.blame.enabled) {257blame(data);258}259}260261function blame(data) {262// If the rendering engine can't handle blame, bail.263if (!data.blame.uri) {264return;265}266267// If we already have an outstanding request for blame data, bail.268if (data.blame.request) {269return;270}271272// If we don't have blame data yet, request it and then try rendering273// again later.274if (!data.blame.value) {275var req = new JX.Request(data.blame.uri, JX.bind(null, onblame, data));276data.blame.request = req;277req.send();278return;279}280281// We're ready to render.282var viewport = JX.$(data.viewportID);283284var row_nodes = JX.DOM.scry(viewport, 'tr');285var row_list = [];286var ii;287288for (ii = 0; ii < row_nodes.length; ii++) {289var row = {};290var keep = false;291var node = row_nodes[ii];292293for (var jj = 0; jj < node.childNodes.length; jj++) {294var child = node.childNodes[jj];295296if (!JX.DOM.isType(child, 'th')) {297continue;298}299300var spec = child.getAttribute('data-blame');301if (spec) {302row[spec] = child;303keep = true;304}305306if (spec === 'info') {307row.lines = child.getAttribute('data-blame-lines');308}309}310311if (keep) {312row_list.push(row);313}314}315316var last = null;317for (ii = 0; ii < row_list.length; ii++) {318var commit = data.blame.value.blame[row_list[ii].lines - 1];319row_list[ii].commit = commit;320row_list[ii].last = last;321last = commit;322}323324for (ii = 0; ii < row_list.length; ii++) {325renderBlame(row_list[ii], data.blame.value);326}327}328329function onblame(data, r) {330data.blame.request = null;331data.blame.value = r;332blame(data);333}334335function renderBlame(row, blame) {336var spec = blame.map[row.commit];337338var info = null;339var skip = null;340341if (spec && (row.commit != row.last)) {342skip = JX.$H(spec.skip);343info = JX.$H(spec.info);344}345346if (row.skip) {347JX.DOM.setContent(row.skip, skip);348}349350if (row.info) {351JX.DOM.setContent(row.info, info);352}353354var epoch_range = (blame.epoch.max - blame.epoch.min);355356var epoch_value;357if (!epoch_range) {358epoch_value = 1;359} else {360epoch_value = (spec.epoch - blame.epoch.min) / epoch_range;361}362363var h_min = 0.04;364var h_max = 0.44;365var h = h_min + ((h_max - h_min) * epoch_value);366367var s = 0.25;368369var v_min = 0.92;370var v_max = 1.00;371var v = v_min + ((v_max - v_min) * epoch_value);372373row.info.style.background = getHSV(h, s, v);374}375376function getHSV(h, s, v) {377var r, g, b, i, f, p, q, t;378379i = Math.floor(h * 6);380f = h * 6 - i;381p = v * (1 - s);382q = v * (1 - f * s);383t = v * (1 - (1 - f) * s);384385switch (i % 6) {386case 0: r = v, g = t, b = p; break;387case 1: r = q, g = v, b = p; break;388case 2: r = p, g = v, b = t; break;389case 3: r = p, g = q, b = v; break;390case 4: r = t, g = p, b = v; break;391case 5: r = v, g = p, b = q; break;392}393394r = Math.round(r * 255);395g = Math.round(g * 255);396b = Math.round(b * 255);397398399return 'rgb(' + r + ', ' + g + ', ' + b + ')';400}401402function onhovercoverage(data, e) {403if (e.getType() === 'mouseout') {404redraw_coverage(data, null);405return;406}407408var target = e.getNode('tag:th');409var coverage = target.getAttribute('data-coverage');410if (!coverage) {411return;412}413414redraw_coverage(data, target);415}416417var coverage_row = null;418function redraw_coverage(data, node) {419if (coverage_row) {420JX.DOM.alterClass(421coverage_row,422'phabricator-source-coverage-highlight',423false);424coverage_row = null;425}426427if (!node) {428JX.Tooltip.hide();429return;430}431432var coverage = node.getAttribute('data-coverage');433coverage = coverage.split('/');434435var idx = parseInt(coverage[0], 10);436var chr = coverage[1];437438var map = data.coverage.labels[idx];439if (map) {440var label = map[chr];441if (label) {442JX.Tooltip.show(node, 300, 'W', label);443444coverage_row = JX.DOM.findAbove(node, 'tr');445JX.DOM.alterClass(446coverage_row,447'phabricator-source-coverage-highlight',448true);449}450}451}452453if (!statics.initialized) {454JX.Stratcom.listen('click', 'document-engine-view-dropdown', onmenu);455statics.initialized = true;456}457458if (config && config.controlID) {459var control = JX.$(config.controlID);460var data = JX.Stratcom.getData(control);461462switch (config.next) {463case 'render':464onview(data, null, true);465break;466case 'blame':467blame(data);468break;469}470471JX.DOM.listen(472JX.$(data.viewportID),473['mouseover', 'mouseout'],474'tag:th',475JX.bind(null, onhovercoverage, data));476}477478});479480481