G2W Ask and Learn

Windows版Github Pages发布脚本

因为需要在 Github Pages 中发布新制作的简历,因此使用了一个 python 的工具 ghp-import,这个工具在 linux 下工作 非常完美,但是到了 windows 上面就会出很多问题,比如:

  • 有可能会损坏一些文件的格式,比如图片和 PDF。
  • 不能识别子目录,比如 doc/myfile.txt 发布后不是存储在 doc 文件夹下,而是存储成了 doc\myfile.txt 文件。

于是经常诸多尝试,写了一个简单的 BAT 文件用来发布子目录作为 Github Pages

@echo off
title Deploying gh-pages ...

if "%1" == "" goto help

if "%1" == ".git" (
    echo Warning:  Can not publish .git directory
    goto end
)

if not exist %1 (
    echo Directory "%1" not found.
    goto end
)

echo Creating gh-pages with directory: %1
git branch -q -D gh-pages
git checkout -q --orphan gh-pages
git rm -r -q --cached .
for /f %%G in ('dir /b .') do ( if not "%%G" == "%1" if not "%%G" == ".git" del /S /F /Q %%G > nul )
move /Y %1\* .  > nul
rd /S /Q %1 > nul
git add .
git commit -m "First Commit"

echo Deploying gh-pages to github pages
git push --force origin gh-pages
git checkout -q -f master
echo Everyting is done.
goto end

:help
echo ghp-import ^<dirname^>
goto end

:end

最新代码可以在 https://gist.github.com/greatghoul/5461633 找到。

用法:

将文件保存为 ghp-import.bat 并放置在环境变量 PATH 的任意目录中,比如: `D:\Python27\Script­s``

在需要发布页面的项目根目录中执行

ghp-import <dirname>

注意: 目前 ghp-import 脚本只支持一级目录,理会深层次的目录就不支持了,不过我后面会改进的。

Markdown幻灯片服务Remarks更新:支持自定主题

Remarks 是一款基于 remark 的幻灯片工具,它允许你在 gist 或者 github 仓库中使用 markdown 来写幻灯片, 然后通过 remarks 的服务自动生成幻灯片并演示,让你更关注于幻灯片的写作,提高效率.

remarks

现在 Remarks 支持自定义幻灯片主题啦,默认情况下,re­marks 会使用官方演示幻灯片的样式作为默认主题.

如果不想使用默认的主题,可能通过 theme 属性指定

title: 这是纪灯片标题
theme: mytheme.css

或者

theme: ../themes/mythemes.css

或者

theme: http://www.mydomain.com/static/mytheme.css

具体示例可以参考:

Remarks 是开源软件,目前布署在 sae 上面: https://github.com/greatghoul/remarks

Google Tasks for Pomotodo V0.5

蕃茄土豆 是一个结合了蕃茄工作法和 GTD 的网页应用程序,是一个体验非常不错的效率工具。

pomogtd 是由一个游猴脚本演变而来,用于将蕃茄土豆中的土豆替换成 Google Tasks

PomoGTD

现在已经升级到了 0.5 版本,允许用户设置是否启用 Google Tasks.

设置菜单

Chrome 商店地址: https://chrome.google.com/webstore/detail/google-tasks-for-pomotodo/ffmjdf­foc­nafipfmjjp­jekakgkoeig­bk

项目地址: https://github.com/GDG-Xian/crx-pomogtd

更新记录

2013-04-25 V0.5

  • 添加是否使用 Google Tasks 替换土豆的开关

2013-03-09 V0.4

  • 忽略 Google Tasks 的 HTTP_HEADERS x-frame-options

2013-01-11 V0.3

  • 增加:Google Tasks 载入过程中显示载入提示效果

2013年4月壁纸分享

最后一次的壁纸分享,以后不会再继续这个主题了,推荐在 http://www.desk­top­nexus.com 上找自己喜欢的.

jqmodal在rails中的简单应用

概述

我以前使用过很多 jquery 模拟对话框的组件,有的简洁,有的炫丽,甚至有的还带N多种可定制的皮肤,但往往的情况是 我们的页面中只需要一种,而且功能好的组件默认的皮肤却并不适合自己页面的风格,于是需要在插件的样式中修改。

于是又有了新的问题,插件的对话框 HTML 结构可能与前端的设计习惯不吻合,或者要改造成满意的样式和结构需要大费周折。

这个时候,jqmodal 就是一个比较好的选择了,因为它除了强大的 API 外,并不限制你使用什么样的 HTML 结构和样式表, 事实上它根本没有提供固定的 HTML 结构和默认皮肤什么的,你完全可以自己定制,于是你想设计成什么样就完全凭自己喜欢了。

而本文要介绍的就是利用 jqmodal 的特性 rails 中实现一个简单的对话框应用。

准备

因为并未找到 jqmodal 相关的 gem,所以你需要手动拷备 jqmodal 的文件到 vendor 中以便调用。

这里下载 jqModal.js 并保存在应用 vendor/assets/javascripts/ 下。

jqmodal 强大的 API 见过里

然后你需要在你的应用的 javascript 中添加 jqModal 的支持

//= require jquery
//= require jquery_ujs
//= require jqModal

jqModal 既然是 jquery 的插件,自然是依赖于 jquery 的,不过需要注意的是,jq­modal 不支持 jquery-1.9.x,所以推荐使用 jquery-1.8.3,所以你需要在 Gemfile 中 jquery 的 gem 锁定在 1.8.3

gem 'jquery-rails', '2.1.4'

扩展

通常的对话框总会伴随着 ajax 内容的加载,网速慢或者数据大的时候,对话框打开时需要较长时间,所以显示一个加载的提示效果 可以更友好一些,这个用 js 就能很轻松搞定,但当对话框中比较多,每个去写就没有必要了。

为了更方便的结合 rails 的 remote 调用,一个比较好的作法是,­modal 默认内容就为加载提示(文字或者图片),触发 remote 调用的同时,打开对话框,显示加载提示,等请求执行完毕,再替换对话框中的内容中新内容。 对话框关闭时。

定义通用的 modal 结构

虽然 jqmodal 可以自由书写 HTML 结构,但在大量应用对话框的时候,完全没有必要重复定义 modal 结构,可以借助 rails 的 helper 来实现一个 modal_tag ,定义好通用的部分,使用时只关心个性的部分就可以了。

修改 app/helpers/application_helper.rb

module ApplicationHelper
  def modal_tag(title, options = {}, &block)
    options = { loading: true }.merge(options)
    locals = { 
      :modal_title => title.nil? ? 'Modal' : title,
      :options => options
    }

    if block_given?
      render :layout => '/layouts/modal', :locals => locals, &block
    else
      render :layout => '/layouts/modal', :locals => locals do 
        if options[:loading] 
          content_tag :span, 'Loading...'
        end
      end
    end
  end
end

添加 app/views/layouts/_modal.html.erb

<div <% if options.has_key?(:id) %>id="<%= options[:id] %>"<% end %> class="jqmWindow <%= options[:class] %>">
  <div class="modal-header">
    <%= modal_title %>
    <a href="#" class="jqmClose">&times;</a>
  </div>

  <div class="modal-content">
    <%= yield %>
  </div>

  <% if options[:loading] %>
  <div class="preloader" style="display: none">Loading...</div>
  <% end %>
</div>

jqmodal 使用 class=jqmWindow 来标识一个元素是对话框,然后该元素内部的 class=jqmClose 来为元素绑定关闭对话框的事件。

这样就可以在 erb 中使用 modal_tag 来快速定义一个对话框的结构了。

<%= modal_tag 'Modal Demo', :id => 'modal_demo' %>

如果不希望显示加载提示,可以这样

<%= modal_tag 'Modal Demo', :id => 'modal_demo', :loading => false %>

扩展 jqmodal

一般来说,modal 的正文并不是 jqmWindow 所在的元素,而是它的子元素(比如 div.modal-content),所以如果要更新 modal 的内容,需要这样:

var $modal = $('#modal-id');
$modal.find('.modal-content').html('Your content here.');

因为更新 modal 正文内容的使用频率非常频繁,所以我们可以写成一个 jqmodal 的扩展。

jQuery ->
  $.fn.extend
    # 更新对话框内容
    jqmUpdate: (html) ->
      $modal = @
      $modal.find('.modal-content').html(html)

    # 自动关闭对话框 自动关闭默认时间为 2000
    # $obj.jqmAutoHide()
    # $obj.jqmAutoHide(1000)
    # $obj.jqmAutoHide(callback)
    # $obj.jqmAutoHide(1000, callback)
    jqmAutoHide: (delay, callback) ->
      $modal = @

      # 如果 delay 为数字,则使用该数字为延迟时间,否则使用系统默认时间
      timeout = if isNaN(delay) then 2000 else parseInt(delay)

      # 根据参数类型,自动选择加调方法
      handler = $.noop
      if $.isFunction(delay)
        handler = delay
      else if $.isFunction(callback)
        handler = callback

      setTimeout () ->
        $modal.jqmHide()
        handler()
      , timeout

为了方便在延迟几秒后关闭对话框,并执行可选的回调函数,我还加了一个 jqmAutoHide 方法扩展。

用法

要使用 jq­modal,需要在页面加载时调用其构造方法进行初始化。

## jqmDialog 扩展方法
# 初始化页面中的对话框
$('.jqmWindow').jqm
  toTop: true
  modal: true
  onHide: (modal) ->
    modal.w.fadeOut () ->
      # 如果弹出窗口内容是ajax读取,则在隐藏时将内容重置为载入动画
      $preloader = modal.w.find('.preloader')
      modal.w.jqmUpdate($preloader.html()) if $preloader.length

      # 清除Overlay
      modal.o.remove() if modal.o

其中 modal: true 表示这是一个模态对话框,并会生成一个遮罩层。

# 绑定了 data-toggle=jqmModel 的元素,会自动寻找 data-target 或者 href 对应的弹出层并打开
$(document).on 'click', '[data-toggle=jqmModal]', (e) ->
  $this = $(@)
  href= $this.attr('href')
  $target = $($this.attr('data-target') or (href && href.replace(/.*(?=#[^\s]+$)/, '')))
  $target.jqmShow()
  e.preventDefault()

然后为 modal 绑定打开事件,只要在元素中加上属性 data-target="jqmModal",则表示点击该元素可以 触发 modal 显示,并且需要加入属性 target="modal-id" 或者 href="#modal-id" 来指定要打开 modal 元素的 id

在 erb 中,对于需要触发 modal 的元素,可以这样设置:

<%= link_to 'Show Modal', show_path, :remote => true, 
  :'data-toggle' => 'jqmModal', 
  :'data-target' => '#modal_demo' %>

这样当点击链接时,会先显示一个对话框(带 loading 的效果),同时后台发送一个 script 类型的 ajax 请求 请求的返回脚本中,用来动态更新对话框的内容。

var $modal = $('#modal_demo');
$modal.jqmUpdate('<%= j(render :partial => 'show') %>');

在这个对话框中如果执行了提交表单之类的操作后需要关闭对话框,可以这样做:

var $modal = $('#modal_demo');
$modal.jqmUpdate('Work is done!');
$modal.jqmAutoHide(function() {
    // Do something ...
});

效果如下:

效果

完整的 demo 可以这里下载。

给Chrome书签栏添加分隔线

一直以来,Chrome 都没有像 Firefox 那样风骚的书签栏分隔线,以致管理仅以 favicon 显示的书签图标,显得杂乱无章。

杂乱的 Chrome 书签栏 Chrome Bookmarks

如果能够使用像 Firefox 那样的分隔线来将书签分组,看起来就会有条理很多。

Firefox Separator

可惜的是, Chrome 并没有提供这样便利的功能,不过强大的网友却并不会因此而放弃,他们使用 favicon 模拟分隔线,效果很赞。

PS: 只要将书签的名称设置为空,则书签则只会以网站的图标显示,­fav­i­con 的实现就是利用了这一机制,将一个页面的图标设置为 分隔线的样子,这样看起来就像一个分隔线了,太伟大了。

访问 http://separator.mayas­tu­dios.com/ ,将里面的 me 链接拖动至书签样,就可以轻松添加一个分隔线了。

Chrome Separator

真是太赞了!

这个网站还提供水平分隔线,不过是通过将书签名称设置为一排 - 来实现的,效果上就不如 Firefox 的赞了。

讨论基于缩进的HTML模板引擎

本文讨论一下基于缩进的HTM­L模板引擎的适用性,例如 jade, slim, haml 等。

什么是缩进式的模板引擎

现在在 ruby/js/python 的社区中流行一些采用类 python 式的缩进语法的HTM­L模板引擎,语法简洁,以缩进来严格控制页面的层次结构,需要通过编译来转换成传统的 HTML 以用于展示。

来看看两个模板语言的区别 erbhaml

erb

<section class=”container”>
  <h1><%= post.title %></h1>
  <h2><%= post.subtitle %></h2>
  <div class=”content”>
    <%= post.content %>
  </div>
</section>

haml

%section.container
  %h1= post.title
  %h2= post.subtitle
  .content
    = post.content

缘由

发起这篇讨论有两个原因。

  1. 一同事坚持一公司项目中使用 slim (之前是使用 Ham­l,含泪劝说后竟然又改成了 slim,现在是项目中是 slim 和 erb 混用)
  2. Seg­ment­Fault 上一个关于 jade 的讨论

讨论

我们先来看看这类模板引擎能够带来哪些好处?

  • 结构清晰:使用缩进来严格控制 DOM 层次,每个人写出来的页面都结构清晰,易于阅读
  • 语法简洁:可以用更少的代码快速的开发页面
  • 省略了闭合标签和 <, > 代码看起来更干净
  • 常用元素属性,例如 idclass 写法类似 CSS,简单高效
  • ....

看起来这类模板引擎开发还是挺方便的,不过仍然无法接受,理由如下:

  • 前端人员难以接受:以于公司的前端和设计,它们有时需要为我们调整页面,不要指望他们会喜欢这种语法, 如果她们同步静态原型和动态页面的修改,将会非常麻烦(项目中开始的原型是最终定稿的情况非常少)
  • 语言支持太少:各 IDE 或者编辑器对它的语法高亮和缩进,补全等的支持有限,虽然我们使用 vim 能比较好的支持, 但我不强制别人也用 vim
  • 太过小众:即便同样是开发,也不见得大家都会习惯这种语法
  • 调试困难:如果页面中某部分出了问题,首先前端会通过 firebug 定位问题出在哪里,如果是普通模板, 直接就找到源码中的目标位置了,如果使用了此类模板,好吧,先用脑子翻译成这种模板,然后再去找目标位置, 如果页面复杂,这种转换需要的时间也就更长。

总之做团队的项目,大家语言模板上一定要统一,这种自己喜欢玩 Geek 的人,会给后面别人维护时带来无穷无尽的麻烦。 简化开发是好事,但是过犹不及。

当然,如果项目成员都对这种模板有较高的接受度,书写简单,结构优美,开发快速,为什么不用呢?

其它讨论

基于remark和github的幻灯片工具 -- Remarks

介绍 Remark Slides 之前,先来介绍下 Remark

Remark 是一个基于 markdown 语法的幻灯片制作工具,要运行它,只需要一个浏览器就足够了,不再需要其它的编译或者转换工具。它通过 JS 版本的 Markdown 解释器来将 Markdown 动态渲染成 HTML 效果并在浏览器中呈现,支持以下功能。

  • 使用 Markdown 编写,并支持一些语法扩展
  • 语法高亮
  • 完善的缩放设计,能够在各种设置上表现一致
  • 支持智能手机和平板上的触摸事件

简言之,Remark 利用了 Markdown 的优势解放了你对于工具的依赖,使你可以专注于幻灯片内容的编写。

而 Remark Slides 则是专为 Github 用户而设计的,你可以在 Gist 或者仓库中创建幻灯片的内容部分,而 Remark Slides 则负责提取你的幻灯片内容并填入预设的 HTML 文件中,你甚至可以切换各种主题模板。

我已经SAE上面部署了应用的雏形 http://remarks.sinaapp.com/

Demo

用法

slides 的源文件,需要写在 slides.md 中,其中为 remark 风格的 slides 源码(仅 markdown 部分),不过需要额外的指定一个 title 属性,以标明 slides 标题,如:

title: 这是纪灯片标题
name: inverse
layout: true
class: inverse
---
...

Gist适合用来存放比较独立的一些 slides,只需要在 gist 中建立一个 slides.md 文件,然后编写内容就可以了。写作完成后可以通过 http://remarks.sinaapp.com/gist/<gist_id> 来访问.

如果有比较多的 slides,放在 gist 里面就比较零乱,这时候可以建立一个 github 仓库来管理 slides,结构如下

/repo/path
  /slides-folder1
    /slides.md
    /picture1.png
    /picture2.png
  /slides-folder2
    /slides.md
    /picture1.png
    /picture2.png

如果将 slides 存储在 repository 中,还可以引用 slides.md 所在目录下的图片文件,不用再单独寻找图床了。

写作好的 slides 可以通过 http://remarks.sinaapp.com/<owner>/<repo>slides-name 来访问。比如 http://remarks.sinaapp.com/greatghoul/slides/slides-folder1/

如果 slides 没有在 master 分支上,还可以通过

http://remarks.sinaapp.com/greatghoul/slides/slides-folder1/?branch=branch-name 来访问

http://remarks.sinaapp.com/ 上还提供了一个 Book­marklet 来方便的把当前的 gist 或者 repository 通过 remarks 打开。

更新历史

2013-04-16

  • 新增:对 Github Repository 的支持
  • 更新:新的 Book­marklet 以支持 gist 和 repo 方式打开
  • 更新:更新 http://remarks.sinaapp.com 的应用介绍

2013-03-13

* 新增了 Book­marklet,可以在 gist 页面点击书签来播放幻灯片

开源

应用于的源码已经放在了 github 上面 ,使用 Flask 开发,都是很简单的代码。

https://github.com/greatghoul/remarks

如果有意见和建议,欢迎在 Issue 中提出。

2013年3月壁纸分享

SkillPages利用用户授权滥用联系人信息

早上收到社区里面有位朋友的 Skillpages 邀请,于是赶紧就注册了,结果因为一时不慎着了道。

邀请信内容

如果使用 Google OAuth2 登陆 Skill­Pages,在授权时请求了很多权限,但因为没有仔细阅读权限列表,结果害人害已。

授权页面

skillpages.com is requesting permission to:

  1. Manage your contacts
    • View and manage your Google Contacts
  2. View basic in­for­ma­tion about your account
    • View your name, public profile URL, and photo
    • View your gender and birthdate
    • View your country, language, and timezone
  3. View your email address
    • View the email address associated with your account

其中 View and manage your Google Contacts 这一项非常危险,它授权应用完全控制你的联系人,不但能拿你所有联系人的信息,还可以管理你的联系人,换句话说,就是把你的联系人全部删除,你也没有脾气。

SkillPages 拿到联系人数据后,以使用者的身份,随机向其联系人发送邀请邮件,目前为止,我已经有4位朋友被我牵连,然后他们也会循环这个过程。

联系人中招

想象一下,这个连锁效应其实很可怕,最后 SkillPages 能够拿到的联系人信息的数量是非常巨大的,然后他们就可以:发送推广广告、虚假中奖信息及钓鱼网站等。

今天早上我还接到了润乾公司售前的电话,询问我发给她的邮件是什么东西,如果这样的事件再多几件,会害死人的。

虽然你可以通过 SkillPages 的设置页面将自己的帐户永久删除,或者通过 Google 的应用授权管理页面移除对 SkillPages 的授权,但其实已经迟了,他们已经拿到了想要的东西。

对于通过用户邮箱联系人邀请用户这样的行为,正规网站的作为是让用户主动去选择邀请哪些朋友,毕竟邀请邮件发送到一些邮件列表的后果是非常严重的,好在 SkillPages 只是伪造使用者姓名,而不是直接拿使用者的邮件发送邀请邮件,可能对一些邮件列表还无法染指。

最近再来联想下国内一些第三方登陆的应用,会不会也出来像 SkillPages 这样的流氓行为?

或者是否应该有这样一款 Chrome 扩展,能够在授权操作时醒目的提示出那些可能比较危险的授权,或者能够大家共享一份用授权胡作非为的网站的黑名单,用户在访问时能够提前得到预警,以避免损失。

Previous